boost::python 和回调驱动的执行

发布于 2024-12-21 14:42:36 字数 3988 浏览 4 评论 0原文

我在涉及 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 的文档来看,似乎有一个对 < code>sem_post(sem),其中 sem 指向信号量。但它指向 NULL。

现在,我怎样才能更准确地查明错误呢?

I'm having problems on a project that involves a boost::python and callback-driven execution.

My project is using a callback mechanism to run some python code from C++.

As long as the initial function call causing my callback execution is coming from the python interpreter, everything is fine. For example:

h = CallbackHandler()

def mycallback():
    print "yeah"

h.setCallback(mycallback)

h.runCallback()

# will print yeah

Alas, it is not that simple. My project uses RtAudio to communicate with the audio environment. RtAudio's execution is callback-driven: I give to RtAudio a callback function, and when I start RtAudio, the callback is called everytime sound needs to be computed.

When using RtAudio's callback-driven execution, I get a segfault as soon as my code tries to run a python callback from C++.

To start the callback-driven execution, I have to make a call to the function start(), which is non-blocking. It means that the callback-driven execution happens in another thread.

Then, when calling start() from python, I'm creating another thread separately accessing python's execution environment. From my little understanding of python's GIL, this is not good.

So, How can I make this callback-driven thread run python callbacks without breaking everything up ?

Sorry, I couldn't find a way to simplify my code to a short, fully functional example of my problem ... the problem is located there.

EDIT

After looking around in the python documentation, I added a few lines of code that are supposed to handle thread safety when a non-python created thread is trying to access to the python environment :

gstate = PyGILState_Ensure();
while (!queue.empty() && queue.top()->next <= now ) {
    queue.top()->run();
    queue.pop();
}
PyGILState_Release(gstate);

But I still get a segfault. So I ran it through valgrind, and here is what I get (minus the weird stuff valgrind always gets from the python interpreter, which is "normal") :

==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)

If I get it right, my callback function is trying to access a NULL pointer right ?

EDIT 2

Ok, I'm discovering all this. From pthread's documentation, it looks like there is a call to sem_post(sem), where sem points to a semaphore. But there it points to NULL.

Now, how can I pinpoint the error more precisely ?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

情何以堪。 2024-12-28 14:42:36

我相信你与 GIL 发生了冲突。我的猜测是回调代码在进入 Python 解释器之前并没有获取 GIL。

也可能是所有要使用 GIL 的线程都必须先注册自己才能这样做。并且执行回调的线程尚未注册本身。

我会对其进行设置,以便 C++ 回调不会执行 Python 回调。相反,它将相关数据写入 Python 程序正在读取的套接字中。然后你的Python程序可以在从套接字获取相关数据时执行回调。

I believe you are running afoul of the GIL. My guess is that the callback code is not acquiring the GIL before diving into the Python interpreter.

It might also be that all the threads that are going to use the GIL have to register themselves before they can do so. And the thread executing your callback has not registered itself.

I would set it up so the C++ callback didn't execute a Python callback. Instead it writes the relevant data into a socket that your Python program is reading from. Then your Python program can execute the callback when it gets the relevant data from the socket.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文