IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> C++ Thread 死锁 -> 正文阅读

[C++知识库]C++ Thread 死锁

死锁示例

  • 线程A与线程B陷入无休止的阻塞状态
std::mutex mx1;
std::mutex mx2;

void thread_func1()
{
	unique_lock<std::mutex> lc1(mx1);
	cout << "1号锁" << endl;
	std::this_thread::sleep_for(std::chrono::microseconds(200));
	unique_lock<std::mutex> lc2(mx2);
	cout << "2号锁" << endl;
}


void thread_func2()
{
	unique_lock<std::mutex> lc2(mx2);
	cout << "2号锁" << endl;
	std::this_thread::sleep_for(std::chrono::microseconds(200));
	unique_lock<std::mutex> lc1(mx1);
	cout << "1号锁" << endl;
}

int main()
{
	thread tha(thread_func1);
	thread thb(thread_func2);
	
	tha.join();
	thb.join();
	return 0;
}

std::mutex mxA;
std::mutex mxB;

int countA = 1000;
int countB = 1000;

void thread_func1(int money)
{
	unique_lock<std::mutex> lcA(mxA);
	std::this_thread::sleep_for(std::chrono::milliseconds(200));
	cout << "线程1获得了A账户的锁" << endl;
	if (countA > money)
	{
		cout << "线程1请求B账户的锁子" << endl;
		unique_lock<std::mutex> lcB(mxB);
		countA -= money;
		countB += money;
		cout << "转账成功A------->B:" << money << endl;
	}
	else
	{
		cout << "A账户的余额不足" << endl;
	}
}

void thread_func2(int money)
{
	unique_lock<std::mutex> lcB(mxA);
	std::this_thread::sleep_for(std::chrono::milliseconds(200));
	cout << "线程2获得了B账户的锁" << endl;
	if (countA > money)
	{
		cout << "线程2请求A账户的锁子" << endl;
		unique_lock<std::mutex> lcA(mxB);
		countB -= money;
		countA += money;
		cout << "转账成功B------->A:" << money << endl;
	}
	else
	{
		cout << "B账户的余额不足" << endl;
	}
}


int main()
{
	thread tha(thread_func1, 200);
	thread thb(thread_func2, 300);

	tha.join();
	thb.join();

	return 0;
}

如何解决死锁

  • 条件变量进行处理
std::mutex mx;
condition_variable cv;
class Count
{
private:
	int money;
public:
	Count(int m) :money(m)
	{}
	~Count() {}

	bool operator<(const Count& src) const
	{
		return money < src.money;
	}
	int GetMoney()const { return money; }
	void SetMoney(int m) { money = m; }
};

class Account
{
public:
	~Account() = default;
	static Account& getInstance()
	{
		//static Account a; //静态变量在函数外进行实例化
		//return a;
		return acc;
	}
	void apply(Count& A, Count& B)
	{
		unique_lock<mutex> lc(mx);
		while (s.count(A) > 0 || s.count(B) > 0)//AB是否有一个存在于集合中
		{	
			cv.wait(lc);
		}
		//两个账户都不在集合中,则将两个账户加入进去
		s.insert(A);
		s.insert(B);//保证两个账户同时插入
	}
	void free(Count& A, Count& B)
	{
		unique_lock<mutex> lc(mx);
		
		s.erase(A);       
		s.erase(B);      
		cv.notify_all();
	}
private:
	Account() = default;
	Account(const Account&) = delete;
	Account& operator=(const Account&) = delete;
	std::set<Count> s;
	static Account acc;
};
Account Account::acc;//进入主函数前进行初始化

void thread_func(Count& A, Count& B, int money)
{
	Account& acc = Account::getInstance();
	acc.apply(A, B);//将AB两个账户加入
	if (A.GetMoney() >= money)
	{
		A.SetMoney(A.GetMoney() - money);
		B.SetMoney(B.GetMoney() + money);
		cout << "success ful" << endl;
		cout << money << endl;
	}
	else
	{
		cout << "余额不足" << endl;
	}
	acc.free(A, B);
}
int main()
{
	Count A(5000);
	Count B(1000);
	Count C(3000);
	Count D(4000);

	std::thread thra(thread_func, std::ref(A), std::ref(B), 500);
	std::thread thrb(thread_func, std::ref(B), std::ref(C), 300);
	std::thread thrc(thread_func, std::ref(C), std::ref(A), 500);
	std::thread thrd(thread_func, std::ref(D), std::ref(A), 300);

	thra.join();
	thrb.join();
	thrc.join();
	thrd.join();

	cout << "A: " << A.GetMoney() << endl;
	cout << "B: " << B.GetMoney() << endl;
	cout << "C: " << C.GetMoney() << endl;
	cout << "D: " << D.GetMoney() << endl;

}

我们定义了一个集合,并且在转账的过程中,要求把两个账户共同写入进去,并且进入等待队列的条件就是集合中存在两个账户

下面是使用map解决原先代码中使用set排序,导致同一个账户在insert的过程中不断的变化继而导致线程的不安全

std::mutex mx;
condition_variable cv;
class Count
{
private:
	string name;
	int money;
public:
	Count() :name(), money(0) {}
	Count(string n,int m) :name(n),money(m)	{}
	~Count() {}

	
	string& getName() { return name; }
	int GetMoney()const { return money; }
	void SetMoney(int m) { money = m; }
};

class Account
{
public:
	~Account() = default;
	static Account& getInstance()
	{
		//static Account a; //静态变量在函数外进行实例化
		//return a;
		return acc;
	}
	void apply(Count& A, Count& B)
	{
		unique_lock<mutex> lc(mx);
		while (s.count(A.getName()) > 0 || s.count(B.getName()) > 0)//AB是否有一个存在于集合中
		{	
			cv.wait(lc);
		}
		//两个账户都不在集合中,则将两个账户加入进去
		s[A.getName()] = A;
		s[B.getName()] = B;
	}
	void free(Count& A, Count& B)
	{
		unique_lock<mutex> lc(mx);
		
		s.erase(A.getName());
		s.erase(B.getName());
		cv.notify_all();
	}
private:
	Account() = default;
	Account(const Account&) = delete;
	Account& operator=(const Account&) = delete;
	std::map<string,Count> s;  //有序不重复 集合
	static Account acc;
};
Account Account::acc;//进入主函数前进行初始化

void thread_func(Count& A, Count& B, int money)
{
	Account& acc = Account::getInstance();
	acc.apply(A, B);//将AB两个账户加入
	if (A.GetMoney() >= money)
	{
		A.SetMoney(A.GetMoney() - money);
		B.SetMoney(B.GetMoney() + money);
		cout << "success ful" << endl;
		cout << money << endl;
	}
	else
	{
		cout << "余额不足" << endl;
	}
	acc.free(A, B);
}
int main()
{
	Count A("zyq",5000);
	Count B("cbq",1000);
	Count C("hxm",3000);
	Count D("scz",1500);

	std::thread thra(thread_func, std::ref(A), std::ref(B), 500);
	std::thread thrb(thread_func, std::ref(B), std::ref(C), 300);
	std::thread thrc(thread_func, std::ref(C), std::ref(A), 500);
	std::thread thrd(thread_func, std::ref(D), std::ref(A), 300);

	thra.join();
	thrb.join();
	thrc.join();
	thrd.join();

	cout << "A: " << A.GetMoney() << endl;
	cout << "B: " << B.GetMoney() << endl;
	cout << "C: " << C.GetMoney() << endl;
	cout << "D: " << D.GetMoney() << endl;
}
  • 通过对两个锁进行同时持有来解决死锁
std::mutex from;
std::mutex to;
condition_variable cv;
class Count
{
private:
	string name;
	int money;
public:
	Count() :name(), money(0) {}
	Count(string n,int m) :name(n),money(m)	{}
	~Count() {}

	
	string& getName() { return name; }
	int GetMoney()const { return money; }
	void SetMoney(int m) { money = m; }
};

class Account
{
public:
	~Account() = default;
	static Account& getInstance()
	{
		//static Account a; //静态变量在函数外进行实例化
		//return a;
		return acc;
	}
	/*
	void apply(Count& A, Count& B)
	{
		unique_lock<mutex> lc(mx);
		while (s.count(A.getName()) > 0 || s.count(B.getName()) > 0)//AB是否有一个存在于集合中
		{	
			cv.wait(lc);
		}
		//两个账户都不在集合中,则将两个账户加入进去
		s[A.getName()] = A;
		s[B.getName()] = B;
	}
	void free(Count& A, Count& B)
	{
		unique_lock<mutex> lc(mx);
		
		s.erase(A.getName());
		s.erase(B.getName());
		cv.notify_all();
	}
	*/
private:
	Account() = default;
	Account(const Account&) = delete;
	Account& operator=(const Account&) = delete;
	std::map<string,Count> s;  //有序不重复 集合
	static Account acc;
};
Account Account::acc;//进入主函数前进行初始化

void thread_func(Count& A, Count& B, int money)
{
	std::unique_lock<std::mutex> lockx(from, std::defer_lock);//暂时不进行锁 预演
	std::unique_lock<std::mutex> locky(to, std::defer_lock);  //代表持有但是不锁

	std::lock(lockx, locky);//同时获得这两个锁
	A.SetMoney(A.GetMoney() - money);
	B.SetMoney(B.GetMoney() + money);
}
int main()
{
	Count A("zyq",5000);
	Count B("cbq",1000);
	Count C("hxm",3000);
	Count D("scz",1500);

	std::thread thra(thread_func, std::ref(A), std::ref(B), 500);
	std::thread thrb(thread_func, std::ref(B), std::ref(C), 300);
	std::thread thrc(thread_func, std::ref(C), std::ref(A), 500);
	std::thread thrd(thread_func, std::ref(D), std::ref(A), 300);

	thra.join();
	thrb.join();
	thrc.join();
	thrd.join();

	cout << "A: " << A.GetMoney() << endl;
	cout << "B: " << B.GetMoney() << endl;
	cout << "C: " << C.GetMoney() << endl;
	cout << "D: " << D.GetMoney() << endl;

}
  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-04-29 11:55:13  更:2022-04-29 11:55:45 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 22:31:33-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码