【问题标题】:is it possible to release the GIL before a C function that blocks and might call back into Python?是否可以在阻塞并可能回调 Python 的 C 函数之前释放 GIL?
【发布时间】:2011-03-01 18:59:45
【问题描述】:

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

Py_BEGIN_ALLOW_THREADS                                                  
blocking_function();
Py_END_ALLOW_THREADS

然而,这个函数碰巧将一个回调指针作为参数。在处理由 C 函数预处理的传入消息时调用此回调。我已经成功地将这个回调封装在一个调用 PyEval_CallObject() 的函数中,允许我向它传递一个 Python 回调。

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

  • 在调用此阻塞操作之前释放 GIL。
  • 让这个阻塞操作安全地回调到 python 解释器中。

这会导致问题吗?如果是这样,有没有办法解决它?

谢谢。

【问题讨论】:

  • 似乎正确的方法可能是在调用PyEval_CallObject 的处理程序中重新捕获 GIL。但是,这意味着将保存的PyThreadState 转发出去,这似乎有点棘手!

标签: python gil python-multithreading python-bindings


【解决方案1】:

几个月前我用过这些API函数,我的回忆有点朦胧,但我相信这段代码会解决你的问题。我假设版本 2.x(3.x 可能不同):

PyGILState_STATE gstate;
gstate = PyGILState_Ensure();

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

PyGILState_Release(gstate);

(以上摘自:Python C/API docs

这基本上是 Py_BEGIN_ALLOW_THREADS/Py_END_ALLOW_THREADS 的倒数 宏。在这些函数中,您释放 GIL,但在 PyGILState 函数中,您获得 GIL。

【讨论】:

  • PyGILState_Ensure/Release API 也适用于 Python 3。
【解决方案2】:

如果我使用全局来存储PyEval_SaveThread 的结果,并在回调中使用它来调用PyEval_RestoreThread,则可以使用。我只需要弄清楚如何通过回调的上下文指针更干净地将其传递给我的代码中的回调。

【讨论】:

  • 既然 PyGILState API 可用,使用它们是一个非常更好的主意(如 dappawit 的回答中所述)。
猜你喜欢
  • 1970-01-01
  • 2013-04-23
  • 1970-01-01
  • 1970-01-01
  • 2021-07-24
  • 2012-06-19
  • 2022-11-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多