我在涉及 boost::python 和回调驱动执行的项目中遇到问题。
我的项目正在使用回调机制从 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 回调呢?
抱歉,我找不到将我的代码简化为我的问题的简短、功能齐全的示例的方法……问题就在那里。
编辑
在查看了python 文档之后,我添加了几行代码,这些代码应该在非 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 的文档中,看起来有一个对 的调用sem_post(sem)
,其中sem
指向一个信号量。但它指向NULL。
现在,我怎样才能更准确地查明错误?