boost::python 和回调驱动的执行
Posted
技术标签:
【中文标题】boost::python 和回调驱动的执行【英文标题】:boost::python and callback driven execution 【发布时间】:2011-12-17 15:44:51 【问题描述】:我在 a project 上遇到问题,涉及 。
我的项目正在使用回调机制从 C++ 运行一些 python 代码。
只要导致我的回调执行的初始函数调用来自 python 解释器,一切都很好。例如:
h = CallbackHandler()
def mycallback():
print "yeah"
h.setCallback(mycallback)
h.runCallback()
# will print yeah
唉,事情没那么简单。我的项目使用RtAudio 与音频环境进行通信。 RtAudio 的执行是回调驱动的:我给 RtAudio 一个回调函数,当我启动 RtAudio 时,每次需要计算声音时都会调用回调。
在使用 RtAudio 的回调驱动执行时,只要我的代码尝试从 C++ 运行 python 回调,就会出现段错误。
要启动回调驱动的执行,我必须调用函数 start(),它是非阻塞的。这意味着回调驱动的执行发生在另一个线程中。
然后,当从 python 调用 start() 时,我正在创建另一个线程,分别访问 python 的执行环境。从我对python的GIL的一点了解来看,这样不好。
那么,我怎样才能让这个回调驱动的线程在不破坏一切的情况下运行 python 回调呢?
抱歉,我找不到将我的代码简化为一个简短、功能齐全的问题示例的方法...the problem is located there。
编辑
在查看python documentation 之后,我添加了几行代码,这些代码应该在非python 创建的线程尝试访问python 环境时处理线程安全:
gstate = PyGILState_Ensure();
while (!queue.empty() && queue.top()->next <= now )
queue.top()->run();
queue.pop();
PyGILState_Release(gstate);
但我仍然遇到段错误。所以我通过 valgrind 运行它,这就是我得到的(减去 valgrind 总是从 python 解释器得到的奇怪的东西,这是“正常的”):
==31836== Thread 2:
==31836== Invalid read of size 4
==31836== at 0x41F0DD5: sem_post@@GLIBC_2.1 (in /lib/libpthread-2.14.1.so)
==31836== by 0x5ED294C: callback(void*, void*, unsigned int, double, unsigned int, void*) (in /home/tom/Code/pyck/pyck/libcore.so)
==31836== by 0x5F6B16B: RtApiAlsa::callbackEvent() (in /usr/lib/librtaudio.so)
==31836== by 0x5F6BBCC: alsaCallbackHandler (in /usr/lib/librtaudio.so)
==31836== by 0x42D286D: clone (in /lib/libc-2.14.1.so)
==31836== Address 0x0 is not stack'd, malloc'd or (recently) free'd
==31836==
==31836==
==31836== Process terminating with default action of signal 11 (SIGSEGV)
==31836== Access not within mapped region at address 0x0
==31836== at 0x41F0DD5: sem_post@@GLIBC_2.1 (in /lib/libpthread-2.14.1.so)
==31836== by 0x5ED294C: callback(void*, void*, unsigned int, double, unsigned int, void*) (in /home/tom/Code/pyck/pyck/libcore.so)
==31836== by 0x5F6B16B: RtApiAlsa::callbackEvent() (in /usr/lib/librtaudio.so)
==31836== by 0x5F6BBCC: alsaCallbackHandler (in /usr/lib/librtaudio.so)
==31836== by 0x42D286D: clone (in /lib/libc-2.14.1.so)
==31836== If you believe this happened as a result of a stack
==31836== overflow in your program's main thread (unlikely but
==31836== possible), you can try to increase the size of the
==31836== main thread stack using the --main-stacksize= flag.
==31836== The main thread stack size used in this run was 8388608.
==31836==
==31836== HEAP SUMMARY:
==31836== in use at exit: 2,313,541 bytes in 2,430 blocks
==31836== total heap usage: 22,140 allocs, 19,710 frees, 22,007,627 bytes allocated
==31836==
==31836== LEAK SUMMARY:
==31836== definitely lost: 522 bytes in 5 blocks
==31836== indirectly lost: 0 bytes in 0 blocks
==31836== possibly lost: 66,669 bytes in 1,347 blocks
==31836== still reachable: 2,246,350 bytes in 1,078 blocks
==31836== suppressed: 0 bytes in 0 blocks
==31836== Rerun with --leak-check=full to see details of leaked memory
==31836==
==31836== For counts of detected and suppressed errors, rerun with: -v
==31836== Use --track-origins=yes to see where uninitialised values come from
==31836== ERROR SUMMARY: 2703 errors from 196 contexts (suppressed: 83 from 13)
如果我做对了,我的回调函数正试图访问一个 NULL 指针,对吗?
编辑 2
好的,我正在发现这一切。从pthread's documentation 看来,有一个对sem_post(sem)
的调用,其中sem
指向一个信号量。但它指向 NULL。
现在,我怎样才能更准确地查明错误?
【问题讨论】:
尝试在 valgrind 下运行程序以更好地诊断问题的根源。 @John : 添加 valgrind 结果 我猜你的信号量问题是你正在使用的队列中的一个实现错误。 【参考方案1】:我认为您违反了 GIL。我的猜测是回调代码在深入 Python 解释器之前没有获取 GIL。
也可能是所有要使用 GIL 的线程都必须先注册自己才能这样做。并且执行你的回调的线程还没有注册自己。
我会设置它,这样 C++ 回调就不会执行 Python 回调。相反,它将相关数据写入 Python 程序正在读取的套接字中。然后你的 Python 程序就可以在从套接字获取相关数据时执行回调了。
【讨论】:
以上是关于boost::python 和回调驱动的执行的主要内容,如果未能解决你的问题,请参考以下文章