Wednesday 15 May 2013

c++ - Python GIL and threads -


I've embedded Python 3 in my big C ++ application. Python gives the ability of the user script for custom data processing.
Problem : I have many threads that interact with Python and how do I really not protect my code with GIL. So far, I'm the only way to get my code working. Using boost :: mutex

Here is a very simple example that reproduces my problem:

  • Thread A call first Init () to start Python (static function).
  • Thread B call Python () Thread to block some work on Python is blocked on first call to lock GIL.

Code :

  #include & lt; Iostream & gt; # Include & lt; Boost / thread.hpp & gt; # Include & lt; Boost / bind.hpp & gt; # Included "Python H" RTMPS_gilock {RTMaps_Gillock () {std :: cout & lt; & Lt; "Locking ..." & lt; & Lt; Std :: endl; M_state = PyGILState_Ensure (); } ~ RTMaps_Gillock () {std :: cout & lt; & Lt; "Unlocking ..." & lt; & Lt; Std :: endl; PyGILState_Release (m_state); } Private: PyGILState_STATE m_state; }; #Galok RTMaps_Gillock Lock Defined; Class python embedded {public: static zero init () {Py_Initialize (); / Edit: Adding those two rows makes my day: PyEval_InitThreads (); // This GIL receives PyEval_SaveThread (); // release GIL zero Python () {Gilko; // never goes here: (std :: cout & lt; "OK" & lt; std :: endl;}}; int main () {Python Embed :: Init (); Python Embedded Python; Promotion :: Thread T (Promotion :: Bind (and Python Embed :: Python, PAT); T. JOIN ();}  

This is deadlock in the first lock call Console Show: Locking

Edit: The correct code, now it is working. I need to release GIL from the main thread.

I had your exact problem, PyGI from the main thread Do not call LState_Ensure (), one is the initialization of Python because it requires a different call. I have finished setting up a thread mapper, and every one of them has to check Python () What this thread is saying is, if it is the main thread, then it uses it:

PyEval_SaveThread ();

Otherwise it stores GIL. There are related sections of my class:

  zero MMana Ger :: acquirePyt value (zero) {MetafieldThisthief = MFramework :: MP Processes :: GetCurrentThread (); If (this thread! = Mainthread) {lock (); Std :: map & lt; MThread, Zero * & gt; :: iterator i = threadStates.find (thisThread); If (i == threadstats.and ()) {unlock (); PyGILState_STATE gstate = PyGilState_Ensure (); _PyGILState_STATE_ * enest = new _PyGILState_STATE_; Anchate-> State = gestate; EncState- & gt; Refnank = 1; Lock (); Threadstats [this thread] = ambettet; Unlock (); } And {_PyGILState_STATE_ * encState = (_PyGILSTATE_STATE _ *) i- & gt; second; EncState-> refCount = encState-> RefCount + 1; Unlock (); }} And {if (Mathematitrate) PyEval_RestoreThread (PyThreadState *) mainstate); }} Void MManager :: releasePython (zero) {this thread = MFramework :: MProcesses :: GetCurrentThread (); If (this thread! = Mainthread) {lock (); Std :: map & lt; MThread, Zero * & gt; :: iterator i = threadStates.find (thisThread); If (i! = ThreadStates.end ()) {_PyGILState_STATE_ * encState = (_PyGILSTATE_STATE _ *) i-> second; If (Anchate-> Refact;> = 1) {threadStates.erase (i); Unlock (); PyGILState_Release (encState- & gt; state); Delete the anchorage; } And {encState-> refCount = encState-> RefCount - 1; Unlock (); }} And {unlock (); }} And {mainThreadState = PyEval_SaveThread (); }}  

No comments:

Post a Comment