pthread_mutex_t死锁

2024-05-07 05:48
文章标签 死锁 pthread mutex

本文主要是介绍pthread_mutex_t死锁,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

互斥量,也叫互斥锁。通常造成死锁的有两种方式:


1.线程A试图对用一个互斥量mutexA加锁两次,那么它自身就会陷入死锁状态,

用伪代码表示就是:


pthreadA:

[cpp] view plain copy
print ?
  1. pthread_mutex_lock(&mutexA)  
  2. pthread_mutex_lock(&mutexA) /* 这里死锁 */  
pthread_mutex_lock(&mutexA)
pthread_mutex_lock(&mutexA) /* 这里死锁 */


2.程序中使用多个互斥量时,如果允许一个线程一直占有第一个互斥量,并且试图锁住第二个互斥量时处于阻塞状态,但是拥有第二个互斥量的线程也在试图锁住第一个互斥量,这时就发生死锁。因为两个线程都在互相请求另一个线程拥有的资源,所以这两个线程都无法向前运行,于是产生死锁。

用伪代码表示就是:


pthreadA:

[cpp] view plain copy
print ?
  1. pthread_mutex_lock(&mutexA)  
  2. pthread_mutex_lock(&mutexB) /* 这里死锁 */  
pthread_mutex_lock(&mutexA)
pthread_mutex_lock(&mutexB) /* 这里死锁 */

pthreadB:

[cpp] view plain copy
print ?
  1. pthread_mutex_lock(&mutexB)  
  2. pthread_mutex_lock(&mutexA) /* 这里死锁 */  
pthread_mutex_lock(&mutexB)
pthread_mutex_lock(&mutexA) /* 这里死锁 */


所以,使用互斥锁的时候一定要注意。

产生死锁的四个必要条件

(1) 互斥条件:一个资源每次只能被一个进程(线程)使用。
(2) 请求与保持条件:一个进程(线程)因请求资源而阻塞时,对已获得的资源保持不放。
(3) 不剥夺条件 : 此进程(线程)已获得的资源,在末使用完之前,不能强行剥夺。
(4) 循环等待条件 : 多个进程(线程)之间形成一种头尾相接的循环等待资源关系。

图 1. 交叉持锁的死锁示意图:
图 1. 交叉持锁的死锁示意图:

注释:在执行 func2 和 func4 之后,子线程 1 获得了锁 A,正试图获得锁 B,但是子线程 2 此时获得了锁 B,正试图获得锁 A,所以子线程 1 和子线程 2 将没有办法得到锁 A 和锁 B,因为它们各自被对方占有,永远不会释放,所以发生了死锁的现象。

使用 pstack 和 gdb 工具对死锁程序进行分析

pstack 在 Linux 平台上的简单介绍

pstack 是 Linux(比如 Red Hat Linux 系统、Ubuntu Linux 系统等)下一个很有用的工具,它的功能是打印输出此进程的堆栈信息。可以输出所有线程的调用关系栈。

gdb 在 Linux 平台上的简单介绍

GDB 是 GNU 开源组织发布的一个强大的 UNIX 下的程序调试工具。Linux 系统中包含了 GNU 调试程序 gdb,它是一个用来调试 C 和 C++ 程序的调试器。可以使程序开发者在程序运行时观察程序的内部结构和内存的使用情况 .

gdb 所提供的一些主要功能如下所示:

1 运行程序,设置能影响程序运行的参数和环境 ;

2 控制程序在指定的条件下停止运行;

3 当程序停止时,可以检查程序的状态;

4 当程序 crash 时,可以检查 core 文件;

5 可以修改程序的错误,并重新运行程序;

6 可以动态监视程序中变量的值;

7 可以单步执行代码,观察程序的运行状态。

gdb 程序调试的对象是可执行文件或者进程,而不是程序的源代码文件。然而,并不是所有的可执行文件都可以用 gdb 调试。如果要让产生的可执行文件可以用来调试,需在执行 g++(gcc)指令编译程序时,加上 -g 参数,指定程序在编译时包含调试信息。调试信息包含程序里的每个变量的类型和在可执行文件里的地址映射以及源代码的行号。gdb 利用这些信息使源代码和机器码相关联。gdb 的基本命令较多,不做详细介绍,大家如果需要进一步了解,请参见 gdb 手册。

清单 1. 测试程序
 #include <unistd.h> #include <pthread.h> #include <string.h> pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER; pthread_mutex_t mutex2 = PTHREAD_MUTEX_INITIALIZER; pthread_mutex_t mutex3 = PTHREAD_MUTEX_INITIALIZER; pthread_mutex_t mutex4 = PTHREAD_MUTEX_INITIALIZER; static int sequence1 = 0; static int sequence2 = 0; int func1() { pthread_mutex_lock(&mutex1); ++sequence1; sleep(1); pthread_mutex_lock(&mutex2); ++sequence2; pthread_mutex_unlock(&mutex2); pthread_mutex_unlock(&mutex1); return sequence1; } int func2() { pthread_mutex_lock(&mutex2); ++sequence2; sleep(1); pthread_mutex_lock(&mutex1); ++sequence1; pthread_mutex_unlock(&mutex1); pthread_mutex_unlock(&mutex2); return sequence2; } void* thread1(void* arg) { while (1) { int iRetValue = func1(); if (iRetValue == 100000) { pthread_exit(NULL); } } } void* thread2(void* arg) { while (1) { int iRetValue = func2(); if (iRetValue == 100000) { pthread_exit(NULL); } } } void* thread3(void* arg) { while (1) { sleep(1); char szBuf[128]; memset(szBuf, 0, sizeof(szBuf)); strcpy(szBuf, "thread3"); } } void* thread4(void* arg) { while (1) { sleep(1); char szBuf[128]; memset(szBuf, 0, sizeof(szBuf)); strcpy(szBuf, "thread3"); } } int main() { pthread_t tid[4]; if (pthread_create(&tid[0], NULL, &thread1, NULL) != 0) { _exit(1); } if (pthread_create(&tid[1], NULL, &thread2, NULL) != 0) { _exit(1); } if (pthread_create(&tid[2], NULL, &thread3, NULL) != 0) { _exit(1); } if (pthread_create(&tid[3], NULL, &thread4, NULL) != 0) { _exit(1); } sleep(5); //pthread_cancel(tid[0]); pthread_join(tid[0], NULL); pthread_join(tid[1], NULL); pthread_join(tid[2], NULL); pthread_join(tid[3], NULL); pthread_mutex_destroy(&mutex1); pthread_mutex_destroy(&mutex2); pthread_mutex_destroy(&mutex3); pthread_mutex_destroy(&mutex4); return 0; }
清单 2. 编译测试程序
 [dyu@xilinuxbldsrv purify]$ g++ -g lock.cpp -o lock -lpthread
清单 3. 查找测试程序的进程号
 [dyu@xilinuxbldsrv purify]$ ps -ef|grep lock dyu       6721  5751  0 15:21 pts/3    00:00:00 ./lock
清单 4. 对死锁进程第一次执行 pstack(pstack –进程号)的输出结果
 [dyu@xilinuxbldsrv purify]$ pstack 6721 Thread 5 (Thread 0x41e37940 (LWP 6722)): #0  0x0000003d1a80d4c4 in __lll_lock_wait () from /lib64/libpthread.so.0 #1  0x0000003d1a808e1a in _L_lock_1034 () from /lib64/libpthread.so.0 #2  0x0000003d1a808cdc in pthread_mutex_lock () from /lib64/libpthread.so.0 #3  0x0000000000400a9b in func1() () #4  0x0000000000400ad7 in thread1(void*) () #5  0x0000003d1a80673d in start_thread () from /lib64/libpthread.so.0 #6  0x0000003d19cd40cd in clone () from /lib64/libc.so.6 Thread 4 (Thread 0x42838940 (LWP 6723)): #0  0x0000003d1a80d4c4 in __lll_lock_wait () from /lib64/libpthread.so.0 #1  0x0000003d1a808e1a in _L_lock_1034 () from /lib64/libpthread.so.0 #2  0x0000003d1a808cdc in pthread_mutex_lock () from /lib64/libpthread.so.0 #3  0x0000000000400a17 in func2() () #4  0x0000000000400a53 in thread2(void*) () #5  0x0000003d1a80673d in start_thread () from /lib64/libpthread.so.0 #6  0x0000003d19cd40cd in clone () from /lib64/libc.so.6 Thread 3 (Thread 0x43239940 (LWP 6724)): #0  0x0000003d19c9a541 in nanosleep () from /lib64/libc.so.6 #1  0x0000003d19c9a364 in sleep () from /lib64/libc.so.6 #2  0x00000000004009bc in thread3(void*) () #3  0x0000003d1a80673d in start_thread () from /lib64/libpthread.so.0 #4  0x0000003d19cd40cd in clone () from /lib64/libc.so.6 Thread 2 (Thread 0x43c3a940 (LWP 6725)): #0  0x0000003d19c9a541 in nanosleep () from /lib64/libc.so.6 #1  0x0000003d19c9a364 in sleep () from /lib64/libc.so.6 #2  0x0000000000400976 in thread4(void*) () #3  0x0000003d1a80673d in start_thread () from /lib64/libpthread.so.0 #4  0x0000003d19cd40cd in clone () from /lib64/libc.so.6 Thread 1 (Thread 0x2b984ecabd90 (LWP 6721)): #0  0x0000003d1a807b35 in pthread_join () from /lib64/libpthread.so.0 #1  0x0000000000400900 in main ()
清单 5. 对死锁进程第二次执行 pstack(pstack –进程号)的输出结果
 [dyu@xilinuxbldsrv purify]$ pstack 6721 Thread 5 (Thread 0x40bd6940 (LWP 6722)): #0  0x0000003d1a80d4c4 in __lll_lock_wait () from /lib64/libpthread.so.0 #1  0x0000003d1a808e1a in _L_lock_1034 () from /lib64/libpthread.so.0 #2  0x0000003d1a808cdc in pthread_mutex_lock () from /lib64/libpthread.so.0 #3  0x0000000000400a87 in func1() () #4  0x0000000000400ac3 in thread1(void*) () #5  0x0000003d1a80673d in start_thread () from /lib64/libpthread.so.0 #6  0x0000003d19cd40cd in clone () from /lib64/libc.so.6 Thread 4 (Thread 0x415d7940 (LWP 6723)): #0  0x0000003d1a80d4c4 in __lll_lock_wait () from /lib64/libpthread.so.0 #1  0x0000003d1a808e1a in _L_lock_1034 () from /lib64/libpthread.so.0 #2  0x0000003d1a808cdc in pthread_mutex_lock () from /lib64/libpthread.so.0 #3  0x0000000000400a03 in func2() () #4  0x0000000000400a3f in thread2(void*) () #5  0x0000003d1a80673d in start_thread () from /lib64/libpthread.so.0 #6  0x0000003d19cd40cd in clone () from /lib64/libc.so.6 Thread 3 (Thread 0x41fd8940 (LWP 6724)): #0  0x0000003d19c7aec2 in memset () from /lib64/libc.so.6 #1  0x00000000004009be in thread3(void*) () #2  0x0000003d1a80673d in start_thread () from /lib64/libpthread.so.0 #3  0x0000003d19cd40cd in clone () from /lib64/libc.so.6 Thread 2 (Thread 0x429d9940 (LWP 6725)): #0  0x0000003d19c7ae0d in memset () from /lib64/libc.so.6 #1  0x0000000000400982 in thread4(void*) () #2  0x0000003d1a80673d in start_thread () from /lib64/libpthread.so.0 #3  0x0000003d19cd40cd in clone () from /lib64/libc.so.6 Thread 1 (Thread 0x2af906fd9d90 (LWP 6721)): #0  0x0000003d1a807b35 in pthread_join () from /lib64/libpthread.so.0 #1  0x0000000000400900 in main ()

连续多次查看这个进程的函数调用关系堆栈进行分析:当进程吊死时,多次使用 pstack 查看进程的函数调用堆栈,死锁线程将一直处于等锁的状态,对比多次的函数调用堆栈输出结果,确定哪两个线程(或者几个线程)一直没有变化且一直处于等锁的状态(可能存在两个线程 一直没有变化)。

输出分析:

根据上面的输出对比可以发现,线程 1 和线程 2 由第一次 pstack 输出的处在 sleep 函数变化为第二次 pstack 输出的处在 memset 函数。但是线程 4 和线程 5 一直处在等锁状态(pthread_mutex_lock),在连续两次的 pstack 信息输出中没有变化,所以我们可以推测线程 4 和线程 5 发生了死锁。

Gdb into thread输出:

清单 6. 然后通过 gdb attach 到死锁进程
   (gdb) info thread 5 Thread 0x41e37940 (LWP 6722)  0x0000003d1a80d4c4 in __lll_lock_wait () from /lib64/libpthread.so.0 4 Thread 0x42838940 (LWP 6723)  0x0000003d1a80d4c4 in __lll_lock_wait () from /lib64/libpthread.so.0 3 Thread 0x43239940 (LWP 6724)  0x0000003d19c9a541 in nanosleep () from /lib64/libc.so.6 2 Thread 0x43c3a940 (LWP 6725)  0x0000003d19c9a541 in nanosleep () from /lib64/libc.so.6 * 1 Thread 0x2b984ecabd90 (LWP 6721)  0x0000003d1a807b35 in pthread_join () from /lib64/libpthread.so.0
清单 7. 切换到线程 5 的输出
 (gdb) thread 5 [Switching to thread 5 (Thread 0x41e37940 (LWP 6722))]#0  0x0000003d1a80d4c4 in __lll_lock_wait () from /lib64/libpthread.so.0 (gdb) where #0  0x0000003d1a80d4c4 in __lll_lock_wait () from /lib64/libpthread.so.0 #1  0x0000003d1a808e1a in _L_lock_1034 () from /lib64/libpthread.so.0 #2  0x0000003d1a808cdc in pthread_mutex_lock () from /lib64/libpthread.so.0 #3  0x0000000000400a9b in func1 () at lock.cpp:18 #4  0x0000000000400ad7 in thread1 (arg=0x0) at lock.cpp:43 #5  0x0000003d1a80673d in start_thread () from /lib64/libpthread.so.0 #6  0x0000003d19cd40cd in clone () from /lib64/libc.so.6
清单 8. 线程 4 和线程 5 的输出
 (gdb) f 3 #3  0x0000000000400a9b in func1 () at lock.cpp:18 18          pthread_mutex_lock(&mutex2); (gdb) thread 4 [Switching to thread 4 (Thread 0x42838940 (LWP 6723))]#0  0x0000003d1a80d4c4 in __lll_lock_wait () from /lib64/libpthread.so.0 (gdb) f 3 #3  0x0000000000400a17 in func2 () at lock.cpp:31 31          pthread_mutex_lock(&mutex1); (gdb) p mutex1 $1 = {__data = {__lock = 2, __count = 0, __owner = 6722, __nusers = 1, __kind = 0, __spins = 0, __list = {__prev = 0x0, __next = 0x0}}, __size = "\002\000\000\000\000\000\000\000B\032\000\000\001", '\000'<repeats 26 times>, __align = 2} (gdb) p mutex3 $2 = {__data = {__lock = 0, __count = 0, __owner = 0, __nusers = 0, __kind = 0, __spins = 0, __list = {__prev = 0x0, __next = 0x0}}, __size = '\000' <repeats 39 times>, __align = 0} (gdb) p mutex2 $3 = {__data = {__lock = 2, __count = 0, __owner = 6723, __nusers = 1, __kind = 0, __spins = 0, __list = {__prev = 0x0, __next = 0x0}}, __size = "\002\000\000\000\000\000\000\000C\032\000\000\001", '\000'<repeats 26 times>, __align = 2} (gdb)

从上面可以发现,线程 4 正试图获得锁 mutex1,但是锁 mutex1 已经被 LWP 为 6722 的线程得到(__owner = 6722),线程 5 正试图获得锁 mutex2,但是锁 mutex2 已经被 LWP 为 6723 的 得到(__owner = 6723),从 pstack 的输出可以发现,LWP 6722 与线程 5 是对应的,LWP 6723 与线程 4 是对应的。所以我们可以得出, 线程 4 和线程 5 发生了交叉持锁的死锁现象。查看线程的源代码发现,线程 4 和线程 5 同时使用 mutex1 和 mutex2,且申请顺序不合理。

小结

本文简单介绍了一种在 Linux 平台下分析死锁问题的方法,对一些死锁问题的分析有一定作用。希望对大家有帮助。理解了死锁的原因,尤其是产生死锁的四个必要条件,就可以最大可能地避免、预防和解除死锁。所以,在系统设计、进程调度等方面注意如何不让这四个必要条件成立,如何确定资源的合理分配算法,避免进程永久占据系统资源。此外,也要防止进程在处于等待状态的情况下占用资源 , 在系统运行过程中,对进程发出的每一个系统能够满足的资源申请进行动态检查,并根据检查结果决定是否分配资源,若分配后系统可能发生死锁,则不予分配,否则予以分配。因此,对资源的分配要给予合理的规划,使用有序资源分配法和银行家算法等是避免死锁的有效方法。


使用上pthread_cond_t遇到的死锁问题 

最近在一个项目中使用pthread_cond_t的时遇到一个死锁的问题,特记录分享一下。这个问题的使用场景很简单,客户端程序起两个线程,一个线程发送数据给服务器,另一个线程接收服务器的返回。发送线程向服务器发送一个数据报,然后等待服务器返回(用pthread_cond_t等待),然后继续发送下一个数据包……,如此循环下去。发送代码抽取出来的逻辑像下面这样:


static void* thread_fun_send(void* nouse)

{

    int send_index = 0;

    while(1)

    {

        //模拟发送数据的socket系统调用

        printf("send %d\n",send_index++);

 

        //通知接收线程可以接收数据

        pthread_mutex_lock(&mutex_send);

        pthread_cond_signal(&cond_send);

        pthread_mutex_unlock(&mutex_send);

 

        //等待收到数据的pthread_cond_t

        pthread_mutex_lock(&mutex_recv);

        pthread_cond_wait(&cond_recv, &mutex_recv);

        pthread_mutex_unlock(&mutex_recv);

    }  

}


接收线程等待服务器的返回,收到服务器返回后给发送线程发信号(用pthread_cond_t发信号),然后继续等待接收服务器下一个返回……,如此循环下去。接收代码抽取出来的逻辑像下面这样:

static void* thread_fun_recv(void* nouse)

{

    int recv_index = 0;

    while(1)

    {  

        //等待收到数据的pthread_cond_t,模拟阻塞的socket

        pthread_mutex_lock(&mutex_send);

        pthread_cond_wait(&cond_send, &mutex_send);

        pthread_mutex_unlock(&mutex_send);

 

        //模拟接收数据的socket系统调用

        printf("recv %d\n",recv_index++);

 

        //通知发送线程数据已经收到

        pthread_mutex_lock(&mutex_recv);

        pthread_cond_signal(&cond_recv);

        pthread_mutex_unlock(&mutex_recv);

    }  

}

就这么一个简单的应用场景,看起来好像是很合乎逻辑的,但在实际的运行中会出现死锁的问题。经过综合分析后发现其实是在理解pthread_cond_t上不准确了,一开始会认为它和windows中的Event是一样的,只是调用的API函数名不同而已,其实它们是不同的。且不说自动重置这个功能,在信号的处理上它们也是完全不同的。在Windows中,当Event被置为有信号时,内核会检查有没有在等待这个信号的线程,如果有则唤醒它,如果没有信号会保存起来,下一个等待此信号的线程进来时会直接获得信号而继续运行;但在Linux中, 如果pthread_cond_t被置为有信号时,内核也是会检查有没有在等待这个信号的线程,如果有则唤醒它,但如果没有等待的线程内核则不会保存这个信号(好像这个信号被丢掉了一样),下一个等待信号的线程进来时是不会获得信号而只会进入睡眠的,只有在睡眠后下一次pthread_cond_t被置为有信号时,这个线程才会被唤醒。


搞清楚了pthread_cond_t和Event的逻辑之后,对于上面这个客户端的业务逻辑,用最小的改动方式就是把使用pthread_cond_t改为sem_t问题就解决了。

附:测试代码,用下面命令即可编译
gcc -o test_cond test_cond.c -pthread

点击(此处)折叠或打开

  1. // File Name: test_cond.c
  2. // Purpose: For Linux pthread_cond_t test
  3. #include <pthread.h>
  4. #include <unistd.h>
  5. #include <stdio.h>
  6. #include <stdlib.h>

  7. static pthread_cond_t cond_send;
  8. static pthread_mutex_t mutex_send;

  9. static pthread_cond_t cond_recv;
  10. static pthread_mutex_t mutex_recv;

  11. static pthread_t thread_send;
  12. static pthread_t thread_recv;

  13. static void* thread_fun_send(void* nouse)
  14. {
  15.     int send_index = 0;

  16.     //wait a moment for recv thread starting up
  17.     sleep(1);

  18.     while(1)
  19.     {
  20.         printf("send %d\n",send_index++);

  21.         pthread_mutex_lock(&mutex_send);
  22.         pthread_cond_signal(&cond_send);
  23.         pthread_mutex_unlock(&mutex_send);

  24.         pthread_mutex_lock(&mutex_recv);
  25.         pthread_cond_wait(&cond_recv, &mutex_recv);
  26.         pthread_mutex_unlock(&mutex_recv);

  27.     }
  28. }

  29. static void* thread_fun_recv(void* nouse)
  30. {
  31.     int recv_index = 0;
  32.     while(1)
  33.     {
  34.         pthread_mutex_lock(&mutex_send);
  35.         pthread_cond_wait(&cond_send, &mutex_send);
  36.         pthread_mutex_unlock(&mutex_send);

  37.         printf("recv %d\n",recv_index++);

  38.         pthread_mutex_lock(&mutex_recv);
  39.         pthread_cond_signal(&cond_recv);
  40.         pthread_mutex_unlock(&mutex_recv);
  41.     }
  42. }

  43. void init()
  44. {
  45.     pthread_mutex_init(&mutex_send, 0);
  46.     pthread_cond_init(&cond_send, 0);

  47.     pthread_mutex_init(&mutex_recv, 0);
  48.     pthread_cond_init(&cond_recv, 0);

  49.     pthread_create(&thread_send, NULL ,thread_fun_send, NULL);
  50.     pthread_create(&thread_recv, NULL ,thread_fun_recv, NULL);
  51. }

  52. void clean()
  53. {
  54.     pthread_cond_destroy(&cond_send);
  55.     pthread_mutex_destroy(&mutex_send);

  56.     pthread_cond_destroy(&cond_recv);
  57.     pthread_mutex_destroy(&mutex_recv);
  58. }


  59. void main()
  60. {
  61.     printf("Test pthread_cond_t applet\n");
  62.     
  63.     init();

  64.     while(1)
  65.     {
  66.         sleep(1);
  67.     }

  68.     clean();
  69.     return;
  70. }

这篇关于pthread_mutex_t死锁的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/966490

相关文章

【Linux修行路】线程安全和死锁

目录 ⛳️推荐 一、线程安全 1.1 常见的线程不安全情况 1.2 常见的线程安全情况 1.3 常见的不可重入情况 1.4 常见可重入的情况 1.5 可重入与线程安全的联系 1.6 可重入与线程安全的区别 二、死锁 2.1 死锁的四个必要条件 2.2 如何避免产生死锁? ⛳️推荐 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大

SylixOS pthread_join退出

1 问题描述 在移植中间件过程中,在SylixOS下调用pthread_join时,如果线程在pthread_join等待之前结束,则线程返回无效线程错误值。在Linux下这种调用会正常返回。两种实现是有差别的,实现的原理分别如下。 2 函数实现机制 2.1 实现机制 在SylixOS下调用pthread_join时,如果线程在pthread_join等待之前结束,线程返回无效线程错误标志

模拟线程死锁——Thread学习笔记

记录一下之前写过的一段模拟死锁的代码: /*** 模拟死锁** @author lixiang* @date 2018年10月12日 - 9:51* @history 2018年10月12日 - 9:51 lixiang create.*/public class HoldLockDemo {private static Object[] lock = new Object[10];priv

【编程底层思考】如何检测和避免线程死锁

一、什么是线程死锁? 线程死锁发生在多个线程因为争夺资源而相互阻塞,导致程序无法正常结束的情况。例如,线程A持有资源2并等待资源1,线程B持有资源1并等待资源2,这样就形成了死锁。 二、如何检测死锁? 使用jmap、jstack等命令行工具查看JVM的线程栈和堆内存情况,jstack可以显示死锁信息。使用VisualVM、JConsole等图形化工具进行排查。例如,JConsole可以连接到

C++11 Thread线程池、死锁、并发

一、线程与进程         进程:运行中的程序         线程:进程中的小进程 二、线程库的使用         包含头文件#include<thread> 2.1 thread函数         具体代码: void show(string str) {cout << "This is my word : " << str << endl;}int main() {t

C++ 的死锁问题的发生和避免

C/C++程序中产生死锁的原因很多,本文大致归纳了下面几类,分别做分析。 1.单线程/进程多次加锁导致死锁 单线程导致死锁的情况一般是由于调用了引起阻塞的函数,比如(copy_from_user()、copy_to_ser()、和kmalloc()),阻塞后进行系统调度,调度的过程中有可能又调用了之前获取锁的函数,这样必然导致死锁。 还有一种就是自旋锁函数在没有释放锁马上又进行申请同一个自旋

Linux基础 -- pthread之线程池任务调度

线程池任务依赖设计方案 1. 设计目标 为了在多线程环境中支持任务间的依赖关系,我们设计了一个基于 pthread_create 封装的线程池,任务之间可以设置依赖,只有在依赖的任务完成后,依赖任务才会被执行。该设计目标是简化任务调度的逻辑,让开发者可以专注于任务的编写,而不必关注复杂的线程管理和任务依赖的执行顺序。 2. 核心概念 2.1 任务(Task) 任务是线程池中执行的最小单位

yt零售系统订单死锁原因

知识前提: InnoDB引擎在加锁的时候,只有通过索引进行检索的时候才会使用行级锁,否则会使用表级锁。 场景: 在订单服务中,开起事务,对同一张表,先更新(无索引),再新增,发生死锁。 原因: 同一线程,更新事务未提交,因为无索引导致了表锁,再新增的时候当前线程等待更新释放锁,会把当前线程挂起来,而锁正是被自己占用,该线程又被挂起而没机会释放锁。 解决方法: 更新的时候在检索列创建索

Oracle:杀死死锁进程

Oracle:杀死死锁进程 1. 模拟死锁现象 利用PL/SQL Developer工具可以很容易模拟死锁现象。用同一个数据库的同一个用户登录2个PL/SQL Developer。 首先,在其中一个PL/SQL Developer随便对数据库的表执行一个更新操作,不要提交,状态为“待提交” 然后,在另一个PL/SQL Developer执行同样的操作,此时这个操作会等待前面的事务提交之后

C++ 有 mutex.lock 为什么要用 lock_guard 、unique_lock

因为直接操作 mutex,即直接调用 mutex 的 lock / unlock 函数。   而使用 lock_guard 可以自动加锁、解锁   C++ Boost库 多线程 线程锁mutex lock_guard 、unique_lock 实例_软件工程小施同学 的专栏-CSDN博客