多线程死锁例程的代码调试 如何避免进入死锁

一、调试代码如下  来源 阅码场https://www.yomocode.com/

void *child1(void *arg)
{
        while(1){
                pthread_mutex_lock(&mutex_1);
                sleep(3);
                pthread_mutex_lock(&mutex_2);
                printf("thread 1 get running \n");
                pthread_mutex_unlock(&mutex_2);
                pthread_mutex_unlock(&mutex_1);
                sleep(5);
        }
}

void *child2(void *arg)
{
        while(1){
                pthread_mutex_lock(&mutex_2);
                pthread_mutex_lock(&mutex_1);
                printf("thread 2 get running \n");
                pthread_mutex_unlock(&mutex_1);
                pthread_mutex_unlock(&mutex_2);
                sleep(5);
        }
}

代码会如下造成死锁现象

LWP 4860   mutex_2  __owner = 4861
LWP 4861   mutex_1 __owner = 4860

线程4860再等4861 线程4861在等4860所以造成死锁

调试如下

一个终端 执行程序

arsenal@arsenal-kernel:~/pthread/day2$ ./a.out 

另一个终端gdb 调试

arsenal@arsenal-kernel:~/pthread/day2$ 
arsenal@arsenal-kernel:~/pthread/day2$ sudo gdb -q -p `pidof a.out`
Attaching to process 4859
[New LWP 4860]
[New LWP 4861]
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
0x00007f68bb6e530d in nanosleep () at ../sysdeps/unix/syscall-template.S:84
84    ../sysdeps/unix/syscall-template.S: 没有那个文件或目录.
(gdb) 
(gdb) thread i      //看所有线程
Invalid thread ID: i
(gdb) i threads
  Id   Target Id         Frame 
* 1    Thread 0x7f68bbe09700 (LWP 4859) "a.out" 0x00007f68bb6e530d in nanosleep
    () at ../sysdeps/unix/syscall-template.S:84
  2    Thread 0x7f68bb618700 (LWP 4860) "a.out" __lll_lock_wait ()
    at ../sysdeps/unix/sysv/linux/x86_64/lowlevellock.S:135
  3    Thread 0x7f68bae17700 (LWP 4861) "a.out" __lll_lock_wait ()
    at ../sysdeps/unix/sysv/linux/x86_64/lowlevellock.S:135
(gdb) thread 2  进入线程2
[Switching to thread 2 (Thread 0x7f68bb618700 (LWP 4860))]   //该线程号为4860
#0  __lll_lock_wait () at ../sysdeps/unix/sysv/linux/x86_64/lowlevellock.S:135
135    ../sysdeps/unix/sysv/linux/x86_64/lowlevellock.S: 没有那个文件或目录.
(gdb) bt
#0  __lll_lock_wait () at ../sysdeps/unix/sysv/linux/x86_64/lowlevellock.S:135
#1  0x00007f68bb9ecdbd in __GI___pthread_mutex_lock (mutex=0x6010c0 )
    at ../nptl/pthread_mutex_lock.c:80
#2  0x00000000004007b0 in child1 (arg=0x0) at deadlock.c:12
#3  0x00007f68bb9ea6ba in start_thread (arg=0x7f68bb618700)
    at pthread_create.c:333
#4  0x00007f68bb72041d in clone ()
    at ../sysdeps/unix/sysv/linux/x86_64/clone.S:109
(gdb) l child1
3    #include
4    pthread_mutex_t mutex_1;
5    pthread_mutex_t mutex_2;
6    
7    void *child1(void *arg)
8    {
9        while(1){
10            pthread_mutex_lock(&mutex_1);
11            sleep(3);
12            pthread_mutex_lock(&mutex_2);
(gdb) p mutex
No symbol "mutex" in current context.
(gdb) p mutex_2
$1 = {__data = {__lock = 2, __count = 0, __owner = 4861, __nusers = 1, 
    __kind = 0, __spins = 0, __elision = 0, __list = {__prev = 0x0, 
      __next = 0x0}}, 
  __size = "\002\000\000\000\000\000\000\000\375\022\000\000\001", '\000' , __align = 2}
(gdb) thread 3
[Switching to thread 3 (Thread 0x7f68bae17700 (LWP 4861))]
#0  __lll_lock_wait () at ../sysdeps/unix/sysv/linux/x86_64/lowlevellock.S:135
135    ../sysdeps/unix/sysv/linux/x86_64/lowlevellock.S: 没有那个文件或目录.
(gdb) bt
#0  __lll_lock_wait () at ../sysdeps/unix/sysv/linux/x86_64/lowlevellock.S:135
#1  0x00007f68bb9ecdbd in __GI___pthread_mutex_lock (mutex=0x601080 )
    at ../nptl/pthread_mutex_lock.c:80
#2  0x00000000004007fa in child2 (arg=0x0) at deadlock.c:24
#3  0x00007f68bb9ea6ba in start_thread (arg=0x7f68bae17700)
    at pthread_create.c:333
#4  0x00007f68bb72041d in clone ()
    at ../sysdeps/unix/sysv/linux/x86_64/clone.S:109
(gdb) l child2
16            sleep(5);
17        }
18    }
19    
20    void *child2(void *arg)
21    {
22        while(1){
23            pthread_mutex_lock(&mutex_2);
24            pthread_mutex_lock(&mutex_1);
25            printf("thread 2 get running \n");
(gdb) p mutex_1
$2 = {__data = {__lock = 2, __count = 0, __owner = 4860, __nusers = 1, 
    __kind = 0, __spins = 0, __elision = 0, __list = {__prev = 0x0, 
      __next = 0x0}}, 
  __size = "\002\000\000\000\000\000\000\000\374\022\000\000\001", '\000' , __align = 2}
(gdb) 

解决方法:
加锁顺序要相同,先拿到锁的后释放锁


二、如何正确加锁

线程安全、可重入问题
三要素
1、同一把锁(同一件事做完)
2、语义整体 ( 事务的概念   我多了你少,你少了我多 )
3、粒度最小

你可能感兴趣的:(多线程编程)