有没有可能先释放GIL,再释放一个阻塞并可能回调到Python中的C函数?

有没有可能先释放GIL,再释放一个阻塞并可能回调到Python中的C函数?,python,gil,python-multithreading,python-bindings,Python,Gil,Python Multithreading,Python Bindings,我正在包装一个C函数,它执行阻塞操作(select),然后处理传入的消息。我的理解是,当C函数要阻塞时,在允许其他线程运行时调用它的正确方法是: Py_BEGIN_ALLOW_THREADS blocking_function(); Py_END_ALLOW_THREADS 但是,该函数碰巧将回调指针作为参数。在处理C函数预处理的传入消息时调用此回调。我已经成功地将这个回调封装在一个调用PyEv

我正在包装一个C函数,它执行阻塞操作(select),然后处理传入的消息。我的理解是,当C函数要阻塞时,在允许其他线程运行时调用它的正确方法是:

Py_BEGIN_ALLOW_THREADS                                                  
blocking_function();
Py_END_ALLOW_THREADS
但是,该函数碰巧将回调指针作为参数。在处理C函数预处理的传入消息时调用此回调。我已经成功地将这个回调封装在一个调用
PyEval\u CallObject()
的函数中,允许我向它传递一个Python回调

现在我正在添加线程支持,我想知道是否可以同时:

  • 在调用此阻塞操作之前释放GIL
  • 让这个阻塞操作安全地回调到python解释器中
这会引起问题吗?如果是这样的话,有办法解决吗


谢谢。

如果我使用全局函数存储
PyEval\u SaveThread
的结果,并在回调中使用此函数调用
PyEval\u RestoreThread
。我只需要弄清楚如何在代码中通过回调的上下文指针更干净地将其传递给回调。

几个月前我使用了这些API函数,我的记忆有点模糊,但我相信这段代码会解决您的问题。我假设版本2.x(3.x可能不同):

(以上摘自:)

这基本上与Py_BEGIN_ALLOW_THREADS/Py_END_ALLOW_THREADS相反
宏。在这些函数中,您可以释放GIL,但在PyGILState函数中,您可以获取GIL。

似乎正确的方法可能是在调用
PyEval\u CallObject的处理程序中重新捕获GIL。但是,这意味着要转发保存的
PyThreadState
,这似乎有点棘手!现在PyGILState API已经可用,使用它们(如dappawit的回答中所述)是一个更好的主意。
PyGILState_STATE gstate;
gstate = PyGILState_Ensure();

/* Make your call to PyEval_CallObject() here (and any other PY API calls). */

PyGILState_Release(gstate);