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;

}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值