我正在编写一个C程序,它使用用python编写的网络库。我用python C api嵌入了python lib。该库发送所有请求异步,并在请求完成时通过信号通知我。
这在理论上意味着。
实际上我有两个与线程相关的问题:
我做错了什么?我是否需要做些什么才能使多线程工作?
答案 0 :(得分:5)
我有类似的情况。
初始工作流程
从一开始,事件线程工作意外。我想这是因为GIL来自我遇到的情况所以我试图从GIL解决这个问题。这是我的解决方案。
<强>分析强>
首先,来自PyEval_InitThreads中的注释,
当只存在主线程时,不需要GIL操作。 ...因此,最初不会创建锁。 ...
因此,如果需要多线程,则必须在主线程中调用PyEval_InitThreads()
。我在PyEval_InitThreads()
之前致电Py_Initialize()
。现在GIL已初始化,主线程获取GIL。
其次,每次从C ++层调用Python函数之前,都会调用PyGILState_Ensure()
来获取GIL。此外,在调用Python函数后,将调用PyGILState_Release(state)
以返回到先前的GIL状态。因此,在步骤2之前,调用PyGILState_Ensure()
,在步骤4之后调用PyGILState_Release(state)
。
但是有一个问题。从PyGILState_Ensure和PyGILState_Release开始,这两个函数用于保存当前GIL状态以获取GIL并恢复之前的GIL状态以释放GIL。但是,在主线程中调用PyEval_InitThreads()
后,主线程肯定拥有GIL。主线程中的GIL状态如下:
/* main thread owns GIL by PyEval_InitThreads */
state = PyGILState_Ensure();
/* main thread owns GIL by PyGILState_Ensure */
...
/* invoke Python function */
...
PyGILState_Release(state);
/* main thread owns GIL due to go back to previous state */
从上面的代码示例中,主线程始终拥有GIL,因此事件线程永远不会运行。为了克服这种情况,让主线程在调用PyGILState_Ensure()
之前不获取GIL。因此,在调用PyGILState_Release(state)
之后,主线程可以释放GIL以让事件线程运行。因此,当GIL初始化时,应立即在主线程中释放GIL。
此处使用PyEval_SaveThread()
。来自PyEval_SaveThread,
释放全局解释器锁(如果已创建并启用了线程支持)并将线程状态重置为NULL,...
通过这样做,嵌入Python的多线程工作。
修改后的工作流程
PyEval_InitThreads();
启用多线程save = PyEval_SaveThread();
在主线程中发布GIL state = PyGILState_Ensure();
在主线程中获取GIL PyGILState_Release(state);
在主线程中发布GIL