[c++] 同一线程两次加锁可能导致死锁问题

前言:

线程间同步的机制很多,最常用的就是各种锁,比如 c++ 11 标准中的 mutex 和 recursive_mutex , 比如 Win32 的 CRITICAL_SECTION 和 Mutex 。 c++开发中我们经常会做一些适用性封装,这也会引入一些潜在的风险,如果不注意的话便可能导致死锁。最常见的就是单线程重复加锁会导致死锁问题。

 

代码:

// ConsoleApplication12.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include <Windows.h>
#include <iostream>
#include <Mutex>
#include <mutex>

using namespace std;

//window Mutex
HANDLE h_m;
//c++ 11 mutex
mutex mu;
//windows CRITICAL_SECTION
CRITICAL_SECTION h_cs;
//c++ 11 recursive_mutex
recursive_mutex r_mu;


//CRITICAL_SECTION NEED INITIALIZATION
int dummy = [](CRITICAL_SECTION& cs)->int {
	InitializeCriticalSection(&cs);
	return 0;
}(h_cs);


void funcB();

void funcA()
{
	//Mutex - no dead lock
	//WaitForSingleObject(h_m, INFINITE);

	//c++ 11 lock_gurad<mutex> - dead lock
	//lock_guard<mutex> lock(mu);

	//c++ 11 mutex - dead lock
	//mu.lock();

	//CRITICAL_SECTION - no dead lock
	//EnterCriticalSection(&h_cs);

	//c++ 11 recursive_mutex - debug mode --> assert is triggered  
    //                         release mode --> OK
	//r_mu.lock();

	//c++ 11 lock_gurad<recursive_mutex> - no dead lock
	lock_guard<recursive_mutex> lock(r_mu);

	funcB();
}

void funcB()
{
	//Mutex - no dead lock
	//WaitForSingleObject(h_m, INFINITE);

	//c++ 11 lock_gurad<mutex> - dead lock
	//lock_guard<mutex> lock(mu);

	//c++ 11 mutex - dead lock
	//mu.lock();

	//CRITICAL_SECTION - no dead lock
	//EnterCriticalSection(&h_cs);

	//c++ 11 recursive_mutex - debug mode --> assert is triggered  
    //                         release mode --> OK
	//r_mu.lock();

	//c++ 11 lock_gurad<recursive_mutex> - no dead lock
	lock_guard<recursive_mutex> lock(r_mu);
}


int main()
{
	h_m = CreateMutex(NULL,FALSE,NULL);

	funcA();

    std::cout << "Hello World!\n";
}


 

小结:

1)如果使用c++ 11进行开发,那么在使用自释放锁 lock_guard 的时候,请配合 recursive_mutex 使用,因为 mutex 有死锁风险,代价就是可能稍微慢那么一点点,不过如果真的要追求效率,请使用CRITICAL_SECTION并自行封装一个自释放锁。

2)CRITICAL_SECTION 是可以单线程重复加锁的,只要在保证有相同数量的解锁 动作即可保证安全。

3)Windows 下的 Mutex 同样可以单线程重复加锁,保证解锁 次数 和加锁次数一致即可保证安全。

4)c++ 11 的mutex 使用一定要注意,单线程重复加锁必定 死锁,其作为 lock_guard 的模板参数也是一样死锁。

5)DEBUG 模式下 recursive_mutex 单线程重复加锁会触发 assert 语句,RELEASE 模式下工作正常。

6)在c++ 工程中,极度不建议使用 mutex , 因为大型工程中很多第三方库通过回调函数的形式进行函数调用,这及其可能导致单线程调用循环,从而导致某个锁被加锁两次而触发死锁。

 

 

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值