[Python-Dev] working with Python threads from C extension module?

Gustavo Carneiro gjcarneiro at gmail.com
Sat Sep 8 17:37:07 CEST 2007


On 08/09/2007, Bill Janssen <janssen at parc.com> wrote:
>
> > Be convoluted yourself and do this:
> >
> > #define PySSL_BEGIN_ALLOW_THREADS { if (_ssl_locks) {
> Py_BEGIN_ALLOW_THREADS
> > #define PySSL_END_ALLOW_THREADS Py_END_ALLOW_THREADS } }
> >
> > (Untested, but I think it should work.)
>
> Yes, that had occurred to me.  We want the code inside the braces
> still to run if the locks aren't held, so something more like
>
>   #define PySSL_BEGIN_ALLOW_THREADS { \
>                         PyThreadState *_save;  \
>                         if (_ssl_locks_count>0) {_save =
> PyEval_SaveThread();}
>   #define PySSL_BLOCK_THREADS   if
> (_ssl_locks_count>0){PyEval_RestoreThread(_save)};
>   #define PySSL_UNBLOCK_THREADS if (_ssl_locks_count>0){_save =
> PyEval_SaveThread()};
>   #define PySSL_END_ALLOW_THREADS       if
> (_ssl_locks_count>0){PyEval_RestoreThread(_save);} \
>                  }
>
> would do the trick.  Unfortunately, this doesn't deal with the macro
> behaviour.  The user has "turned on" threading; they expect reads and
> writes to yield the GIL so that other threads can make progress.  But
> the fact that threading has been "turned on" after the SSL module has
> been initialized, means that threads don't work inside the SSL code.
> So the user's understanding of the system will be broken.
>
> No, I don't see any good way to fix this except to add a callback
> chain inside PyThread_init_thread, which is run down when threads are
> initialized.  Any module which needs to set up threads registers itself
> on that chain, and gets called as part of PyThread_init_thread.  But
> I'm far from the smartest person on this list :-), so perhaps someone
> else will see a good solution.


I think this is a helpful additional tool to solve threading problems.
Doesn't solve everything, but it certainly helps :-)

For instance, one thing it doesn't solve is when a library being wrapped can
be initialized with multithreading support, but only allows such
initialization as a very first API call; you can't initialize threading at
any arbitrary time during application runtime.  Unfortunately I don't think
there is any sane way to fix this problem :-(

This has got to be a problem with other extension modules linked to
> libraries which have their own threading abstractions.


Yes.

Another problem is that python extensions may not wish to incur performance
penalty of python threading calls.  For instance, pyorbit has these macros:

#define pyorbit_gil_state_ensure() (PyEval_ThreadsInitialized()?
(PyGILState_Ensure()) : 0)

#define pyorbit_gil_state_release(state) G_STMT_START { \
    if (PyEval_ThreadsInitialized())                    \
        PyGILState_Release(state);                      \
    } G_STMT_END

#define pyorbit_begin_allow_threads             \
    G_STMT_START {                              \
        PyThreadState *_save = NULL;            \
        if (PyEval_ThreadsInitialized())        \
            _save = PyEval_SaveThread();

#define pyorbit_end_allow_threads               \
        if (PyEval_ThreadsInitialized())        \
            PyEval_RestoreThread(_save);        \
    } G_STMT_END

They all call PyEval_ThreadsInitialized() before doing anything thread
related to save some performance.  The other reason to do it this way is
that the Python API calls themselves abort if they are called with threading
not initialized.  It would be nice the upstream python GIL macros were more
like pyorbit and became no-ops when threading is not enabled.

-- 
Gustavo J. A. M. Carneiro
INESC Porto, Telecommunications and Multimedia Unit
"The universe is always one step beyond logic." -- Frank Herbert
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://mail.python.org/pipermail/python-dev/attachments/20070908/5d3a01f6/attachment.htm 


More information about the Python-Dev mailing list