我正在尝试开发一个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将挂起#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不支持守护程序线程吗?这似乎与section 23.2.2.1 of the documentation建议的不一致:GDB可能不是线程安全的,但我不认为它应该在启动这样一个愚蠢的守护程序线程后挂起。
答案 0 :(得分:2)
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安装(sudo pip install pysigset)。