带回调的pthread与Python虚拟机
假设我有一个Python脚本,它通过ctypes加载了一个共享库(SL)。
- 这个共享库设置了一个名为T1的线程。
- Python脚本通过这个共享库配置了回调函数,也就是说,Python脚本调用共享库中的函数,并传入Python中的可调用对象(函数)。
这里有个图示 http://www.gliffy.com/pubdoc/1993061/L.jpg
现在,假设T1调用了一个“回调”函数,以下假设是否正确:
- 在Python这边的回调函数是在T1的上下文中执行的。
- 我可以使用一个队列来在T1和Python虚拟机之间进行通信。
- 我需要在Python虚拟机这边轮询(检查)这个队列。
我理解线程、共享状态等概念,但对Python的多线程部分还没有深入研究。由于有一个我目前还不太了解的适配层(ctypes),我担心会错过一些关键的过程细节。
2 个回答
0
这个可以很简单地用Cython来实现。我在这里写了一个示例,地址是 https://github.com/sachinpc/cython/tree/master/Demos/mt_callback
这个例子展示了如何在Cython中包装Python的回调函数,当它是从一个pthread(线程)调用时。针对你的具体需求,你可以在回调函数中向线程代码添加一个队列(Queue)或出队列(dequeue)对象。在这个示例中,我在扩展中添加了打印语句,用于显示pthread的ID和Python线程的ID。
1
通常情况下,不需要频繁地去检查队列(你可以在Python那边开一个线程,专门用来执行阻塞的.get
调用),不过这也没什么大不了的。问题在于,如果这样安排的话,你可能会受到全局解释器锁(GIL)的影响——可以参考这个维基百科页面上的三个链接,里面有详细的解释。
当你用Python的C API和C(或者Cython)代码进行交互时,你可以比较简单地释放和获取GIL,希望这样能避免死锁等问题;而使用ctypes时,GIL的操作会在从C调用和回调时自动处理,所以如果还有其他锁在起作用,就有可能出现死锁的风险(因为这些事情不在你的控制之下,你无法轻易确保Dijkstra的银行家算法被正确应用)。