gpt4 book ai didi

不同线程和 GIL 上的 Python 回调

转载 作者:行者123 更新时间:2023-12-03 13:03:47 25 4
gpt4 key购买 nike

我将属于多线程 C 框架的 C 函数包装在 python 模块中。在这个框架中,当某些事件被触发时会执行回调。但是,回调并不总是从同一个线程执行。

与我的问题相关的回调在 python ctypes 中定义。普通 ctypes 回调的问题在于它们尝试使用 python C-API 获取 GIL。当从未调用 Py_initialize() 的线程运行时,此获取失败.

由于框架的原因,我无法更改回调的执行方式,我唯一能做的就是更改回调函数本身。

为了控制获取 GIL 的方式,我创建了一个 C 回调函数,它包装了 python 回调函数:

void* callback(void*){
if (PyGILState_GetThisThreadState()) {
PyGILState_STATE gstate;
gstate = PyGILState_Ensure();
PyRun_SimpleString(...);
PyGILState_Release(gstate);
} else {
PyRun_SimpleString(...);
}
}

如果 PyGILState_GetThisThreadState()函数返回一个非 NULL 值,这意味着回调是从与 Py_initialize() 相同的线程执行的。被称为。这意味着可以使用 PyGILState API。这工作正常。
else当从其他线程运行回调时执行部分。如果它是该线程堆栈上唯一的python调用,它将被正确执行,但是当堆栈中有未完成的python调用时,它将导致段错误:
#0  0x0000003c46ce6cdb in PyImport_GetModuleDict () from /usr/lib64/libpython2.6.so.1.0
#1 0x0000003c46ce6d2b in PyImport_AddModule () from /usr/lib64/libpython2.6.so.1.0`
#2 0x0000003c46cf2fe8 in PyRun_SimpleStringFlags () from /usr/lib64/libpython2.6.so.1.0
...
<framework calls>
...
#19 0x0000003c46cf1daa in PyRun_StringFlags () from /usr/lib64/libpython2.6.so.1.0
#20 0x0000003c46cf3010 in PyRun_SimpleStringFlags () from /usr/lib64/libpython2.6.so.1.0
#21 0x00007fc72c78dbb6 in execString () from ...

我也尝试将 PyGILState API 用于 else 部分,但它会导致相反的情况:连续 python 调用的回调成功,但当它是堆栈中的第一个 python 调用时会导致死锁:
#0  0x0000003c8de0da00 in sem_wait () from /lib64/libpthread.so.0
#1 0x0000003c46cfd428 in PyThread_acquire_lock () from /usr/lib64/libpython2.6.so.1.0
#2 0x0000003c46cd7784 in PyEval_RestoreThread () from /usr/lib64/libpython2.6.so.1.0
#3 0x0000003c46cf0f58 in PyGILState_Ensure () from /usr/lib64/libpython2.6.so.1.0

如果我以与 if(PyGILState_GetThisThreadState()){..} 相同的方式获得 GIL 状态部分,带有 PyGILState_EnsurePyGILState_Release ,它会在堆栈中有较早的python调用时正常工作,但在堆栈中没有python调用时不会。

有没有办法确定回调是要进行第一个 python 还是连续调用?或者也许是解决这个线程问题的一种方法?

最佳答案

显然我可以使用 _PyThreadState_Current ,我仍然不能 100% 确定为什么会这样,但确实如此。好像应该是currentThread而不是 !currentThread .

void callback(){
PyThreadState * currentThread = _PyThreadState_Current;
if (PyGILState_GetThisThreadState() || !currentThread){
PyGILState_STATE gstate;
gstate = PyGILState_Ensure();
PyRun_SimpleString(....);
PyGILState_Release(gstate);
}else{
PyRun_SimpleString(....);
}

感谢 this post为我指明了正确的方向。

关于不同线程和 GIL 上的 Python 回调,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40488242/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com