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

C/C++程序中产生死锁的原因很多,本文大致归纳了下面几类,分别做分析。

1.单线程/进程多次加锁导致死锁

单线程导致死锁的情况一般是由于调用了引起阻塞的函数,比如(copy_from_user()、copy_to_ser()、和kmalloc()),阻塞后进行系统调度,调度的过程中有可能又调用了之前获取锁的函数,这样必然导致死锁。

还有一种就是自旋锁函数在没有释放锁马上又进行申请同一个自旋锁,这样的低级问题也是会导致自旋锁。

简单的说,就是在单个线程中,创建了一个不可重复加锁的锁,然后,调用了加锁函数,在没有调用解锁函数的情况下,再次调用加锁函数导致的死锁。

例如,std::recursive_mutex 是可重复加锁的Recursive锁,std::mutex是不可重复加锁的NonRecursive锁。下面的例子中,在main函数中,分别创建了一个Recursive锁,一个NonRecursive锁:

#include <chrono>
#include <iostream>
#include <mutex>

int main(int argc, char *argv[])
{
    std::mutex              mutex;
    std::recursive_mutex    mutex_recursive;

    while(true)
    {
        //Recursive锁,尝试多次加锁
        mutex_recursive.lock();
        std::cout << "11111" << std::endl;
        mutex_recursive.lock();
        std::cout << "22222" << std::endl;
        mutex_recursive.unlock();
        std::cout << "33333" << std::endl;
        mutex_recursive.unlock();

        //NonRecursive锁,尝试多次加锁
        mutex.lock();
        std::cout << "AAAAAAA" << std::endl;
        mutex.lock();
        std::cout << "BBBBBBB" << std::endl;
        mutex.unlock();
        std::cout << "CCCCCC" << std::endl;
        mutex.unlock();

        std::this_thread::sleep_for(std::chrono::milliseconds(5000));
    }
    
    return 0;
}

以上程序输出:

11111
22222
33333
AAAAAAA

从输出看,输出“AAAAAAA”后,第二次对NonRecursive类型的锁加锁,程序就卡住不往下执行了。可见,对于Recursive类型的锁,同一个线程多次加锁都不会死锁;但是,对于NonRecursive类型的锁,同一个线程多次加锁,就会导致死锁。

综上所述,对于单线程/进程程序,只要创建Recursive类型的锁,就可以保证不发生死锁问题。

2.多线程/进程的死锁

大多数情况下,程序发生的死锁都是发生在多线程/进程情况下,因为,相对于单线程/进程程序,多线程/进程程序在代码执行时序上会更复杂,程序员更不好把握。

出现以下四种情况会产生死锁:

2.1 忘记解锁

两个线程/ 进程共享同一个资源,考虑如下时序:

1.其

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值