GDB多线程调试总结

文章通过两个示例展示了多线程编程中可能出现的问题。第一个例子说明了未正确使用互斥锁导致的并发问题,通过gdb调试工具观察到变量a的非连续变化。第二个例子演示了死锁的情况,两个线程各自持有不同锁并尝试获取对方的锁,造成阻塞。解决方法是确保线程获取锁的顺序一致性。
摘要由CSDN通过智能技术生成

demo

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#include <iostream>
using namespace std;
long int  a = 0;
pthread_mutex_t mutex;
pthread_mutex_t mutex2;
void* threadFunc(void *arg)
{
    // pthread_mutex_lock(&mutex);
    for(int i = 0; i < 500000; i++)
    {
        a = a+1;
    }
    // pthread_mutex_unlock(&mutex);
    // pthread_mutex_lock(&mutex2);
}
void* threadFunc2(void *arg)
{
    // pthread_mutex_lock(&mutex2);
    for(int i = 500000; i < 1000000; i++)
    {
        a = a+1;
    }
    // pthread_mutex_unlock(&mutex2);
    // pthread_mutex_lock(&mutex);
}
int main(int argc,char **argv)
{
    pthread_t thread1,thread2;
    // pthread_create(&thread1 ,NULL, threadFunc,NULL);
    pthread_create(&thread1, NULL, threadFunc, NULL);
    pthread_create(&thread2 ,NULL, threadFunc2,NULL);
    pthread_join(thread1,NULL);
    pthread_join(thread2,NULL);
    cout << "value a = " << a << endl;
    return 0;
}

1 多线程编译及调试

# 1 编译生成带符号信息的程序
g++ multhread.cpp  -g -lpthread  -o test_thread# 2 开始调试程序
gdb ./test_thread 
# 3 显示源程序
layout next

此时会显示如下:

输入下面的命令 “r”继续运行程序

屏幕显示错乱,可在gdb命令下输入refresh刷新。

# 刷新屏幕并给函数增加断点
(gdb) refresh
(gdb) b threadFunc
Breakpoint 1 at 0x4009de: file multhread.cpp, line 16.
(gdb) b threadFunc2
Breakpoint 2 at 0x400a11: file multhread.cpp, line 27.

此时代码中有断点的位置显示“b+”

输入如下命令运行程序:

(gdb) r
Starting program: /home/ren/Desktop/test/test02/test_thread
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
[New Thread 0x7ffff6f4e700 (LWP 36510)]
[New Thread 0x7ffff674d700 (LWP 36511)]
[Switching to Thread 0x7ffff6f4e700 (LWP 36510)]
Thread 2 "test_thread" hit Breakpoint 1, threadFunc (arg=0x0) at multhread.cpp:16
# 查看线程信息
(gdb) info threads
  Id   Target Id         Frame
  1    Thread 0x7ffff7fb5740 (LWP 36507) "test_thread" clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:81
* 2    Thread 0x7ffff6f4e700 (LWP 36510) "test_thread" threadFunc (arg=0x0) at multhread.cpp:16
  3    Thread 0x7ffff674d700 (LWP 36511) "test_thread" threadFunc2 (arg=0x0) at multhread.cpp:27
# 调试线程2
(gdb) thread 2
[Switching to thread 2 (Thread 0x7ffff6f4e700 (LWP 36510))]
#0  threadFunc (arg=0x0) at multhread.cpp:16
#查看堆栈调用信息(可以看到线程创建过程 clone -> start_thread )
(gdb) where
#0  threadFunc (arg=0x0) at multhread.cpp:16
#1  0x00007ffff7bc16ba in start_thread (arg=0x7ffff6f4e700) at pthread_create.c:333
#2  0x00007ffff757551d in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:109
(gdb) watch a
Hardware watchpoint 4: a
#不断输入c发现a的值不是连续变化的,说明有其他线程在修改a
(gdb) c
Continuing.
Thread 3 "test_thread" hit Hardware watchpoint 3: a
Old value = 4
New value = 6
Thread 3 "test_thread" hit Hardware watchpoint 4: a
Old value = 4
New value = 6
threadFunc2 (arg=0x0) at multhread.cpp:27
# 观察所有线程a的变化
(gdb) thread apply all watch a
Thread 3 (Thread 0x7ffff674d700 (LWP 36511)):
Hardware watchpoint 5: a
Thread 2 (Thread 0x7ffff6f4e700 (LWP 36510)):
Hardware watchpoint 6: a
Thread 1 (Thread 0x7ffff7fb5740 (LWP 36507)):
Hardware watchpoint 7: a
(gdb) 8 in /home/ren/Desktop/test/test02/multhread.cpp
#反复输入c观察所有线程的变量a的变化,发现每个线程中a变化都不是连续的
(gdb) c
Continuing.
[Switching to Thread 0x7ffff674d700 (LWP 36511)]
Thread 3 "test_thread" hit Hardware watchpoint 3: a
Old value = 18
New value = 19
Thread 3 "test_thread" hit Hardware watchpoint 4: a
Old value = 18
New value = 19
Thread 3 "test_thread" hit Hardware watchpoint 5: a

2 典型的死锁调试

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#include <iostream>
using namespace std;
long int  a = 0;
pthread_mutex_t mutex;
pthread_mutex_t mutex2;
void* threadFunc(void *arg)
{
    pthread_mutex_lock(&mutex);
    for(int i = 0; i < 5000; i++)
    {
        a = a+1;
        sleep(2);
    }
    pthread_mutex_lock(&mutex2);
    cout<<"threadFunc value a = "<<a<<endl;
    pthread_mutex_unlock(&mutex);
    pthread_mutex_unlock(&mutex2);
}
void* threadFunc2(void *arg)
{
    pthread_mutex_lock(&mutex2);
    for(int i = 5000; i < 10000; i++)
    {
        a = a+1;
        sleep(2);
    }
    pthread_mutex_lock(&mutex);
    cout<<"threadFunc2 value a = "<<a<<endl;
    pthread_mutex_unlock(&mutex);
    pthread_mutex_unlock(&mutex2);
}
int main(int argc,char **argv)
{
    pthread_t thread1,thread2;
    // pthread_create(&thread1 ,NULL, threadFunc,NULL);
    pthread_create(&thread1, NULL, threadFunc, NULL);
    pthread_create(&thread2 ,NULL, threadFunc2,NULL);
    pthread_join(thread1,NULL);
    pthread_join(thread2,NULL);
    cout << "value a = " << a << endl;
    return 0;
}

编译及调试

g++ multhread2.cpp  -g -lpthread  -o test_thread2
gdb  ./test_thread2

进入gdb调试

(gdb) r
Starting program: /home/ren/Desktop/test/test02/test_thread2 
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
[New Thread 0x7ffff6f4e700 (LWP 38558)]
[New Thread 0x7ffff674d700 (LWP 38559)]
^C
Thread 1 "test_thread2" received signal SIGINT, Interrupt.
0x00007ffff7bc298d in pthread_join (threadid=140737336633088, thread_return=0x0) at pthread_join.c:90
90      pthread_join.c: No such file or directory.
(gdb) info threads 
  Id   Target Id         Frame 
* 1    Thread 0x7ffff7fb5740 (LWP 38554) "test_thread2" 0x00007ffff7bc298d in pthread_join (threadid=140737336633088, 
    thread_return=0x0) at pthread_join.c:90
  2    Thread 0x7ffff6f4e700 (LWP 38558) "test_thread2" 0x00007ffff753a38d in nanosleep () at ../sysdeps/unix/syscall-template.S:84
  3    Thread 0x7ffff674d700 (LWP 38559) "test_thread2" 0x00007ffff753a38d in nanosleep () at ../sysdeps/unix/syscall-template.S:84
(gdb) thread 3
[Switching to thread 3 (Thread 0x7ffff674d700 (LWP 38559))]
#0  0x00007ffff753a38d in nanosleep () at ../sysdeps/unix/syscall-template.S:84
84      ../sysdeps/unix/syscall-template.S: No such file or directory.
(gdb) bt
#0  0x00007ffff753a38d in nanosleep () at ../sysdeps/unix/syscall-template.S:84#1  0x00007ffff753a2da in __sleep (seconds=0) at ../sysdeps/posix/sleep.c:55
#2  0x0000000000400ba6 in threadFunc2 (arg=0x0) at multhread2.cpp:33
#3  0x00007ffff7bc16ba in start_thread (arg=0x7ffff674d700) at pthread_create.c:333
#4  0x00007ffff757551d in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:109
(gdb) thread 2
[Switching to thread 2 (Thread 0x7ffff6f4e700 (LWP 38558))]
#0  0x00007ffff753a38d in nanosleep () at ../sysdeps/unix/syscall-template.S:84
84      in ../sysdeps/unix/syscall-template.S
(gdb) bt
#0  0x00007ffff753a38d in nanosleep () at ../sysdeps/unix/syscall-template.S:84#1  0x00007ffff753a2da in __sleep (seconds=0) at ../sysdeps/posix/sleep.c:55
#2  0x0000000000400b09 in threadFunc (arg=0x0) at multhread2.cpp:19
#3  0x00007ffff7bc16ba in start_thread (arg=0x7ffff6f4e700) at pthread_create.c:333
#4  0x00007ffff757551d in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:109 
#以下命令会让所有线程都执行这个命令,比如命令为bt,查看所有线程的具体的栈信息,常用(gdb) thread apply all bt 
Thread 3 (Thread 0x7ffff6fee700 (LWP 39888)):
#0  0x00007ffff78bc38d in nanosleep () at ../sysdeps/unix/syscall-template.S:84
#1  0x00007ffff78bc2da in __sleep (seconds=0) at ../sysdeps/posix/sleep.c:55
#2  0x00000000004008a3 in threadFunc2 (arg=0x0) at multhread2.c:30
#3  0x00007ffff7bc16ba in start_thread (arg=0x7ffff6fee700) at pthread_create.c:333
#4  0x00007ffff78f751d in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:109
Thread 2 (Thread 0x7ffff77ef700 (LWP 39887)):
#0  0x00007ffff78bc38d in nanosleep () at ../sysdeps/unix/syscall-template.S:84
#1  0x00007ffff78bc2da in __sleep (seconds=0) at ../sysdeps/posix/sleep.c:55
#2  0x0000000000400821 in threadFunc (arg=0x0) at multhread2.c:16
#3  0x00007ffff7bc16ba in start_thread (arg=0x7ffff77ef700) at pthread_create.c:333
#4  0x00007ffff78f751d in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:109
Thread 1 (Thread 0x7ffff7fb7700 (LWP 39883)):
#0  0x00007ffff7bc298d in pthread_join (threadid=140737345681152, thread_return=0x0) at pthread_join.c:90
#1  0x000000000040094f in main (argc=1, argv=0x7fffffffd9f8) at multhread2.c:46

thread apply all bt 很有用

解决方法:

加锁顺序要相同,先拿到锁的后释放锁

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值