当前位置: 首页 > article >正文

c++介绍锁四

对于多线程来说导致死锁的原因较多,最简单的一个原因是锁定一个互斥量后,没有释放这个互斥量,导致其它的线程获取这个互斥量时,会永远进入阻塞状态,往往发生在程序分支较多或者抛出异常时忘记主动释放,解决方法:lock_guard或者unique_lock这样的自动对象,对互斥量进行管理,这样离开作用域后,在析构函数中自动释放互斥量。

另一个原因,同时对多个互斥量进行锁定和解锁时,由于获得和释放互斥量顺序不同容易造成死锁。

例如

#include<array>
#include<thread>
#include<iostream>
#include<mutex>
using namespace std;

class DemoClass
{
public:
	void func1()
	{
		{
			lock_guard<mutex> lock1(mtx1);
			lock_guard<mutex>lock2(count_mtx);
			count++;
			cout << "[func1]count=" << count << "\n";
		}
		this_thread::sleep_for(1ms);
	}
	void func2()
	{
		{
			lock_guard<mutex>lock1(count_mtx);
			lock_guard<mutex>lock2(mtx1);
			count--;
			cout << "[fuc2]Count=" << count << "\n";
		}
		this_thread::sleep_for(1ms);
	}
	void calc(int n)
	{
		for (int i = 0; i < n; i++)
		{
			if (n % 2)
			{
				func2();
			}
			else
			{
				func1();
			}
		}	
	}
private:
	mutex mtx1;
	mutex count_mtx;
	int count = 0;
};
void main()
{
	DemoClass demo;
	const int n1 = 10000;
	const int n2 = 10001;
	thread th1(&DemoClass::calc,&demo,n1);
	thread th2(&DemoClass::calc,&demo, n2);

	th1.join();
	th2.join();
}

运行结果 

程序运行一段时间后发生死锁。

线程1获取mtx1等待获取count_mtx,而线程2获取count_mtx等待获取mtx这样程序永远进入阻塞状态。

改进方法1代码如下

#include<array>
#include<thread>
#include<iostream>
#include<mutex>
using namespace std;

class DemoClass
{
public:
	void func1()
	{
		while (true){
			unique_lock<timed_mutex> lock1(mtx1,defer_lock);
			unique_lock<timed_mutex>lock2(count_mtx,defer_lock);
			if (!lock1.try_lock_for(100ms))
				continue;
			if (!lock2.try_lock_for(100ms))
				continue;
			count++;
			cout << "[func1]count=" << count << "\n";
		}
		this_thread::sleep_for(1ms);
	}
	void func2()
	{
		while(true){
			unique_lock<timed_mutex>lock1(count_mtx,defer_lock);
			unique_lock<timed_mutex>lock2(mtx1,defer_lock);
			if (!lock1.try_lock_for(100ms))
				continue;
			if (!lock2.try_lock_for(100ms))
				continue;
			count--;
			cout << "[fuc2]Count=" << count << "\n";
		}
		this_thread::sleep_for(1ms);
	}
	void calc(int n)
	{
		for (int i = 0; i < n; i++)
		{
			if (n % 2)
			{
				func2();
			}
			else
			{
				func1();
			}
		}	
	}
private:
	timed_mutex mtx1;
	timed_mutex count_mtx;
	int count = 0;
};
void main()
{
	DemoClass demo;
	const int n1 = 10000;
	const int n2 = 10001;
	thread th1(&DemoClass::calc,&demo,n1);
	thread th2(&DemoClass::calc,&demo, n2);

	th1.join();
	th2.join();
}

使用计时锁如果在100ms内为获取到想获取得锁,释放当前拥有得锁,进入下一次循环,这样程序进入到活锁得状态,两个线程不断得释放自己当前拥有得锁,而又得不到想获取得锁。

解决活锁得方法:保证顺序获得互斥量

#include<array>
#include<thread>
#include<iostream>
#include<mutex>
using namespace std;

class DemoClass
{
public:
	void func1()
	{
			lock(mtx1,count_mtx);
			lock_guard<mutex> lock1(mtx1,adopt_lock);
			lock_guard<mutex> lock2(count_mtx, adopt_lock);
			count++;
			cout << "[func1]count=" << count << "\n";
		   this_thread::sleep_for(1ms);
	}
	void func2()
	{
			lock(mtx1, count_mtx);
			lock_guard<mutex> lock1(mtx1, adopt_lock);
			lock_guard<mutex> lock2(count_mtx, adopt_lock);
			count--;
			cout << "[fuc2]Count=" << count << "\n";
		   this_thread::sleep_for(1ms);
	}
	void calc(int n)
	{
		for (int i = 0; i < n; i++)
		{
			if (n % 2)
			{
				func2();
			}
			else
			{
				func1();
			}
		}	
	}
private:
	mutex mtx1;
	mutex count_mtx;
	int count = 0;
};
void main()
{
	DemoClass demo;
	const int n1 = 10000;
	const int n2 = 10001;
	thread th1(&DemoClass::calc,&demo,n1);
	thread th2(&DemoClass::calc,&demo, n2);

	th1.join();
	th2.join();
}

算法大致原理

线程1拥有互斥量A,线程2拥有互斥量b,当前程1尝试获取互斥量b时,获取失败,线程1释放互斥量a,此时线程2获取互斥量a成功,线程2再获取互斥量c,拥有所有资源后执行线程2.线程2执行完毕后释放互斥量a,b,c。线程1获取互斥量a,b,c.执行线程1。

任何一个下线程在等待资源得时候,不能够锁定任何资源。如果已经获得资源,那么需要释放资源,再进入阻塞状态。即防止死锁条件得破环请求保持条件。

此外还可以使用scope_lock类更加方便。


http://www.kler.cn/a/579607.html

相关文章:

  • 快速排序(二叉树的前序递归遍历思想)
  • 【three.js】动画系统完全指南 - 从事件循环到工业级动画架构
  • MobileBERT: 一种适用于资源有限设备的紧凑型任务无关BERT
  • 关于C/C++语言的初学者在哪刷题,怎么刷题
  • 软件系统压力测试方案,压力测试报告模版(Word原件)
  • OSPF-单区域的配置
  • 反射是什么?
  • 数学建模-1:对变化建模
  • Python正则表达式完全指南:从入门到精通
  • 【Linux网络(一)】初始网络
  • Linux:多线程(单例模式,其他常见的锁,读者写者问题)
  • ESP8266UDP透传
  • 华为Mate 60 Pro+ 等机型适配支持运营商北斗卫星短信功能
  • C++:vector容器(下篇)
  • Milvus的匹配语法
  • 二维码识别OCR接口:开启高效信息提取的新篇章
  • RK Android14 在计算器内输入特定字符跳转到其他应用
  • 文件上传漏洞测试
  • Java 大视界 -- Java 大数据在智慧交通信号灯智能控制中的应用(116)
  • TCP/IP 5层协议簇:网络层(ICMP协议)