使用多线程python扩展调试多线程程序时,GDB挂起

沉默的

我正在尝试开发GDB python扩展,该扩展定义了一个启动新线程的命令,用户可以在其中检查任意类型的变量。我的python扩展程序的框架是这样的:

import gdb
import threading

def plot_thread():
    import time
    while True:
        print('Placeholder for a window event loop.')
        time.sleep(1)
        pass
    pass

class PlotterCommand(gdb.Command):
    def __init__(self):
        super(PlotterCommand, self).__init__("plot",
                                            gdb.COMMAND_DATA,
                                            gdb.COMPLETE_SYMBOL)
        self.dont_repeat()
        pass

    def invoke(self, arg, from_tty):
        plot_thread_instance=threading.Thread(target=plot_thread)
        plot_thread_instance.daemon=True
        plot_thread_instance.start()
        pass

    pass

PlotterCommand()

可以看出,我在这里定义了plot命令。当我尝试调试以下程序时,如果执行以下操作,GDB将挂起:

  1. 在procedure()线程内的任何地方放置断点(例如,while循环内的第9行)。
  2. gdb达到断点后运行命令
  3. 之后继续运行
#include <iostream>
#include <thread>

using namespace std;

void procedure() {
    cout << "before loop"<<endl;
    while(1) {
        cout << "loop iteration"<<endl;
    }
}

int main() {
    thread t(procedure);
    t.join();
    return 0;
}

最奇怪的是,如果我更改此代码以在不启动线程的情况下调用procedure(),则GDB永远不会挂起(并且占位符消息仍按我的预期进行打印)。

到目前为止,我已经尝试在GDB 7.5.1和7.10版本中运行此过程,但是我始终会遇到相同的行为。

我究竟做错了什么?GDB不支持守护程序线程吗?这似乎与文档的23.2.2.1节所建议的不符:GDB可能不是线程安全的,但我认为在启动这样一个愚蠢的守护程序线程后,它不应挂起。

沉默的

这篇博客文章

GDB使用此函数(sigsuspend,GDB挂起的函数)等待应用程序执行中的新事件:当调试对象中发生某些事件(请参阅调试器的工作原理)时,内核将通过发送SIGCHLD信号将其通知GDB。收到消息后,GDB醒来并检查发生了什么。

但是,信号被传递到GDB进程,但不一定传递到其主线程。实际上,它经常发生在传递给第二个线程时,该线程不关心它(这是默认行为),并且像没有发生任何事情一样继续其生命。

解决方案是配置线程信号处理行为,以便仅GDB主线程通过这些信号得到通知:

import gdb
import threading
import pysigset, signal # Import these packages!

def plot_thread():
    import time
    while True:
        print('Placeholder for a window event loop.')
        time.sleep(1)
        pass
    pass

class PlotterCommand(gdb.Command):
    def __init__(self):
        super(PlotterCommand, self).__init__("plot",
                                            gdb.COMMAND_DATA,
                                            gdb.COMPLETE_SYMBOL)
        self.dont_repeat()
        pass

    def invoke(self, arg, from_tty):
        with pysigset.suspended_signals(signal.SIGCHLD): # Disable signals here!
            plot_thread_instance=threading.Thread(target=plot_thread)
            plot_thread_instance.daemon=True
            plot_thread_instance.start()
            pass
        pass

    pass

PlotterCommand()

所述pysigset包是必需的,并且可以从PIP被安装(须藤PIP安装pysigset)。

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章