从C工作线程调用Py_EndInterpreter

时间:2019-09-18 14:08:55

标签: python c python-3.x python-embedding

对Python PyEval_ReleaseLock的弃用在我们的代码库中引入了一个问题:我们想使用Py_EndInterpreter从C回调函数终止Python解释器

为此,Python's Docs说,在调用此函数时必须按住GIL:

  

无效Py_EndInterpreter(PyThreadState * tstate)

     

销毁由给定线程状态表示的(子)解释器。给定的线程状态必须为   当前线程状态。请参阅下面的线程状态讨论。通话返回时,   当前线程状态为NULL。与该解释器关联的所有线程状态均被销毁。 (   全局解释器锁必须在调用此函数之前保持,并且在返回时仍保持)   Py_FinalizeEx()将销毁当时尚未明确销毁的所有子解释器。

太好了!因此,我们调用PyEval_RestoreThread将线程状态恢复到将要终止的线程,然后调用Py_EndInterpreter

// Acquire the GIL
PyEval_RestoreThread(thread);

// Tear down the interpreter.
Py_EndInterpreter(thread);

// Now what? We still hold the GIL and we no longer have a valid thread state.
// Previously we did PyEval_ReleaseLock here, but that is now deprecated.

PyEval_ReleaseLock的文档说我们应该使用PyEval_SaveThreadPyEval_ReleaseThreadPyEval_ReleaseThread的文档说输入线程的状态不能为NULL。好的,但是我们不能传递最近删除的线程状态。

PyEval_SaveThread将在您调用Py_EndInterpreter之后尝试调用调试断言,因此也不是选择。

因此,我们目前已实现了一种解决该问题的方法-我们将调用Py_InitializeEx的线程的线程状态保存在全局变量中,并在调用Py_EndInterpreter之后将其交换。

// Acquire the GIL
PyEval_RestoreThread(thread);

// Tear down the interpreter.
Py_EndInterpreter(thread);

// Swap to the main thread state.
PyThreadState_Swap(g_init.thread_state_);
PyEval_SaveThread(); // Release the GIL. Probably.

这里的正确解决方案是什么?似乎嵌入式Python是此API的事后建议。

相似的问题:PyEval_InitThreads in Python 3: How/when to call it? (the saga continues ad nauseam)

0 个答案:

没有答案