python threads in c

  • Last Update :
  • Techknowledgy :
  • initialize the Python environment at the very begining:
/*define a global variable to store the main python thread state*/
PyThreadState * mainThreadState = NULL;

if (!Py_IsInitialized())
   Py_Initialize();

mainThreadState = = PyThreadState_Get();
  • Then start the C threads:
pthread_create(pthread_id, NULL, thread_entrance, NULL);
  • prepare the environment:
/*get the lock and create new python thread state*/
PyEval_AcquireLock();
PyInterpreterState * mainInterpreterState = mainThreadState - > interp;
PyThreadState * myThreadState = PyThreadState_New(mainInterpreterState);
PyEval_ReleaseLock(); /*don't forget to release the lock*/

/*
 * some C manipulations here
 */
  • when every thread finishes their works, finalize the python environment
pthread_join(pthread_id, NULL);
PyEval_RestoreThread(mainThreadState);
Py_Finalize();

Suggestion : 2

In an application embedding Python, the Py_Initialize() function must be called before using any other Python/C API functions; with the exception of a few functions and the global configuration variables.,Initialize the Python interpreter. In an application embedding Python, this should be called before using any other Python/C API functions; see Before Python Initialization for the few exceptions.,Changed in version 3.2: This function cannot be called before Py_Initialize() anymore.,All of the following functions must be called after Py_Initialize().

"3.0a5+ (py3k:63103M, May 12 2008, 00:53:55) \n[GCC 4.2.3]"
"[GCC 2.7.2.2]"
"#67, Aug  1 1997, 22:34:28"
PyRun_SimpleString("import sys; sys.path.pop(0)\n");
Save the thread state in a local variable.
Release the global interpreter lock.
   ...Do some blocking I / O operation...
   Reacquire the global interpreter lock.
Restore the thread state from the local variable.
Py_BEGIN_ALLOW_THREADS
   ...Do some blocking I / O operation...
   Py_END_ALLOW_THREADS

Suggestion : 3

Then we add a PyThread_type_lock (an opaque pointer) to the Python structure we are intending to protect. I’ll use the example of the SkipList source code. Here is a fragment with the important lines highlighted:,Thread A tries to insert a Python object into the SkipList. The C++ code searches for a place to insert it preserving the existing order. To do so it must call back into Python code for the user defined comparison function (using functools.total_ordering for example).,At this point the Python interpreter is free to make a context switch allowing thread B to, say, remove an element from the SkipList. This removal may well invalidate C++ pointers held by thread A.,If your Extension is likely to be exposed to a multi-threaded environment then you need to think about thread safety. I had this problem in a separate project which was a C++ SkipList which could contain an ordered list of arbitrary Python objects. The problem in a multi-threaded environment was that the following sequence of events could happen:

#include <Python.h>
   #include "structmember.h"

   #ifdef WITH_THREAD
   #include "pythread.h"
   #endif
typedef struct {
   PyObject_HEAD
   /* Other stuff here... */
   #ifdef WITH_THREAD
   PyThread_type_lock lock;
   #endif
}
SkipList;
 1
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
#ifdef WITH_THREAD
/* A RAII wrapper around the PyThread_type_lock. */
class AcquireLock {
   public: AcquireLock(SkipList * pSL): _pSL(pSL) {
         assert(_pSL);
         assert(_pSL - > lock);
         if (!PyThread_acquire_lock(_pSL - > lock, NOWAIT_LOCK)) {
            Py_BEGIN_ALLOW_THREADS
            PyThread_acquire_lock(_pSL - > lock, WAIT_LOCK);
            Py_END_ALLOW_THREADS
         }
      }
      ~AcquireLock() {
         assert(_pSL);
         assert(_pSL - > lock);
         PyThread_release_lock(_pSL - > lock);
      }
   private: SkipList * _pSL;
};
#else
/* Make the class a NOP which should get optimised out. */
class AcquireLock {
   public: AcquireLock(SkipList * ) {}
};
#endif
if (!PyThread_acquire_lock(_pSL - > lock, NOWAIT_LOCK)) {
   {
      PyThreadState * _save;
      _save = PyEval_SaveThread();
      PyThread_acquire_lock(_pSL - > lock, WAIT_LOCK);
      PyEval_RestoreThread(_save);
   }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15