我有C ++ dll,可以使用多个线程。 所以我用Cython包装了这个库并创建了特殊的接收器回调函数,它必须在asyncio.Queue中添加一些结果。
cdef void __cdecl NewMessage(char* message) nogil:
我把它标记为nogil,这个回调来自另一个线程。 在这个回调中我只使用:
with gil:
print("hello") # instead adding to Queue. print("hello") is more simple operation to demostrate problem
这里遇到了僵局。 如何解决?
C ++回调声明(标题):
typedef void (*receiver_t)(char*);
void SetReceiver(receiver_t new_rec);
CPP:
static receiver_t receiver = nullptr;
void SetReceiver(receiver_t new_rec)
{
printf("setted%i\n", (int)new_rec);
a = 123;
if (new_rec != nullptr)
receiver = new_rec;
}
Cython代码:
cdef extern from "TeamSpeak3.h":
ctypedef void (*receiver_t) (char*) nogil
cdef void __cdecl SetReceiver(receiver_t new_rec) nogil
cdef void __cdecl NewMessage(char* message) nogil:
with gil:
print("hello")
SetReceiver(NewMessage)
完整代码: .h http://pastebin.com/ZTCjc6NA
.cpp http://pastebin.com/MeygA8im
答案 0 :(得分:1)
这是一个猜测,但你可能有一个Cython / C / C ++循环运行,持有GIL并且从不释放它。然后强制回调等待它。
在普通的Python代码中,如果另一个线程正在等待它,则每隔几条指令释放一次GIL。在Cython中不会自动发生。确保它经常发生的一种方法是循环:
while True:
# ... do stuff
with nogil:
pass
这确保了每个循环释放一次GIL。
不幸的是,对于我有主循环的地方来说,这并不明显。我想知道它是否在connect
类中的PyTeamSpeak3
内,并且可能将连接的定义更改为:
def connect(self):
with nogil:
self.thisptr.Connect()
可能会有帮助吗?