死锁 3个月前

编程语言
622
死锁

当多个线程访问共享资源, 需要加锁, 如果锁使用不当, 就会造成死锁这种现象。 线程死锁造成的后果是:所有的线程都被阻塞,并且线程的阻塞是无法解开的(因为可以解锁的线程也被阻塞了)。

造成死锁的场景有如下几种:

  • 加锁之后没有解锁
// 场景1
void func()
{
    for(int i=0; i<6; ++i)
    {
        // 当前线程A加锁成功, 当前循环完毕没有解锁, 在下一轮循环的时候自己被阻塞了
        // 其余的线程也被阻塞
        pthread_mutex_lock(&mutex);
        ....
        .....
        // 忘记解锁
    }
}

// 场景2
void func()
{
    for(int i=0; i<6; ++i)
    {
        // 当前线程A加锁成功
        // 其余的线程被阻塞
        pthread_mutex_lock(&mutex);
        ....
        .....
        if(xxx)
        {
            ...;
            return ;// 函数退出, 没有解锁(解锁函数无法被执行了)
        }
        
        pthread_mutex_lock(&mutex);
    }
}
  • 重复加锁,造成死锁
void func()
{
    for(int i=0; i<6; ++i)
    {
        // 当前线程A加锁成功
        // 其余的线程阻塞
        pthread_mutex_lock(&mutex);
        // 锁被锁住了, A线程阻塞
        pthread_mutex_lock(&mutex);
        ....
        .....
        pthread_mutex_unlock(&mutex);
    }
}

// 隐藏的比较深的情况
void funcA()
{
    for(int i=0; i<6; ++i)
    {
        // 当前线程A加锁成功
        // 其余的线程阻塞
        pthread_mutex_lock(&mutex);
        ....
        .....
        pthread_mutex_unlock(&mutex);
    }
}

void funcB()
{
    for(int i=0; i<6; ++i)
    {
        // 当前线程A加锁成功
        // 其余的线程阻塞
        pthread_mutex_lock(&mutex);
        funcA();        // 重复加锁
        ....
        .....
        pthread_mutex_unlock(&mutex);
    }
}
  • 在程序中有多个共享资源, 因此有很多把锁,随意加锁,导致相互被阻塞

场景描述:

  1. 有两个共享资源:X, Y,X对应锁A, Y对应锁B
    • 线程A访问资源X, 加锁A
    • 线程B访问资源Y, 加锁B
  2. 线程A要访问资源Y, 线程B要访问资源X,因为资源X和Y已经被对应的锁锁住了,因此这个两个线程被阻塞
    • 线程A被锁B阻塞了, 无法打开A锁
    • 线程B被锁A阻塞了, 无法打开B锁

image

在使用多线程编程的时候,如何避免死锁呢?

  • 避免多次锁定, 多检查

  • 对共享资源访问完毕之后, 一定要解锁,或者在加锁的使用 trylock

  • 如果程序中有多把锁, 可以控制对锁的访问顺序(顺序访问共享资源,但在有些情况下是做不到的),另外也可以在对其他互斥锁做加锁操作之前,先释放当前线程拥有的互斥锁。

  • 项目程序中可以引入一些专门用于死锁检测的模块

image
EchoEcho官方
无论前方如何,请不要后悔与我相遇。
1377
发布数
439
关注者
2222765
累计阅读

热门教程文档

Vue
25小节
CSS
33小节
Javascript
24小节
Golang
23小节
Java
12小节