GDB死锁调试
1、测试代码
代码中开启两个线程,加锁后轮流输出数据,其中一个线程误将pthread_mutex_unlock(),写成pthread_mutex_lock()代码如下:
int g_tickets = 100; pthread_mutex_t g_mutex = PTHREAD_MUTEX_INITIALIZER; void* thread_fun1(void * arg) { while(true) { pthread_mutex_lock(&g_mutex); if(g_tickets>0) { cout<<"thread 1 sell tickets:"<<g_tickets--<<endl; } else { //pthread_mutex_unlock(&g_mutex); pthread_mutex_lock(&g_mutex);//误将pthread_mutex_unlock写成pthread_mutex_lock break; } //pthread_mutex_unlock(&g_mutex); pthread_mutex_lock(&g_mutex);//误将pthread_mutex_unlock写成pthread_mutex_lock } return (void*)1; } void* thread_fun2(void * arg) { while(true) { pthread_mutex_lock(&g_mutex); if(g_tickets>0) { cout<<"thread 2 sell tickets:"<<g_tickets--<<endl; } else { pthread_mutex_unlock(&g_mutex); break; } pthread_mutex_unlock(&g_mutex); } return (void*)2; } int main() { pthread_t tid1,tid2; void *ret1 = nullptr; void *ret2 = nullptr; pthread_create(&tid1,nullptr,thread_fun1,nullptr); pthread_create(&tid2,nullptr,thread_fun2,nullptr); pthread_join(tid1,&ret1); pthread_join(tid2,&ret2); cout<<"ret1:"<<ret1<<endl; cout<<"ret2:"<<ret2<<endl; return 0; }
makefile文件
cc =g++ -g -std=c++2a -fmodules-ts prom = main deps = $(shell find ./ -name "*.h") src = $(shell find ./ -name "*.cpp") obj = $(src:%.cpp=%.o) lib = -lboost_thread \ -lboost_system \ -pthread $(prom):$(obj) $(cc) -o $(prom) $(obj) $(lib) %.o:%.cpp $(deps) $(cc) -c $< -o $@ $(lib)
2、编译并运行程序
make ./main
输入结果如下
3、调试
- 查找测试程序进程号
ps aux | grep main
- 通过gdb attach死锁进程。
sudo gdb main 23848
- 使用info threads命令列出所有线程信息
- 切换到线程2 ,并打印调用栈
- 切换到线程3,并打印调用栈
- 打印互斥变量信息,发现锁g_mutex被线程23849获得。而线程23849和23850均在尝试获得锁g_mutex。
- 通过源码分析,发现thread_fun1中g_mutex在获得锁之后,后续并没有释放锁g_mutex,而且在继续申请锁g_mutex。明显不合理。