<三>线程间互斥-mutex互斥锁和lock_guard

多线程程序
竞态条件:多线程程序执行的结果是一致的,不会随着CPU对线程不同的调用顺序而产生不同的运行结果.

解决?:互斥锁 mutex

经典的卖票问题,三个线程卖100张票

代码1

#include <iostream>
#include <thread>
#include <list>
#include <mutex>
int ticketCount = 100;

std::mutex mtx;//互斥锁


void sellTicket(int window) {

	while (ticketCount > 0) {
		
		mtx.lock();
		std::cout << "窗口" << window << "销售" << ticketCount << std::endl;	
		ticketCount--;
		mtx.unlock();
		
		std::this_thread::sleep_for(std::chrono::milliseconds(50));	
		
	}

}//end



int main() {

	std::list<std::thread> tlist;
	
	for (int i = 0; i < 3; i++) {
		tlist.push_back(std::thread(sellTicket,i));
	}

	for (std::thread & t : tlist) {
		t.join();
	}

	system("pause");
	return 0;
}

上面代码的问题...

while (ticketCount > 0) {
		
    mtx.lock();
    std::cout << "窗口" << window << "销售" << ticketCount << std::endl;	
    ticketCount--;
    mtx.unlock();		
    std::this_thread::sleep_for(std::chrono::milliseconds(50));	
		
}
如果ticketCount =1 ,当前有一个线程A while (ticketCount > 0)为true,线程A还没执行ticketCount--完成时,cpu交给了线程B
线程B while (ticketCount > 0)也为true,进入 循环体内,造成了买0号票,改进如下

代码2

#include <iostream>
#include <thread>
#include <list>
#include <mutex>
int ticketCount = 100;

std::mutex mtx;//互斥锁


void sellTicket(int window) {

	while (ticketCount > 0) {
		
		mtx.lock();
                if(ticketCount >0){
		  std::cout << "窗口" << window << "销售" << ticketCount << std::endl;	
		  ticketCount--;
                }
		mtx.unlock();		
		std::this_thread::sleep_for(std::chrono::milliseconds(50));			
	}

}//end



int main() {

	std::list<std::thread> tlist;
	
	for (int i = 0; i < 3; i++) {
		tlist.push_back(std::thread(sellTicket,i));
	}

	for (std::thread & t : tlist) {
		t.join();
	}

	system("pause");
	return 0;
}

代码2还有些问题!! 如下

mtx.lock();
代码
代码
代码
代码
.....
mtx.unlock();	

如果在代码lock()和unlock()之间 非常返回,导致mtx没有正常unlock(),那么出现死锁问题 =》智能指针  lock_gurad unique_lock

看lock_gurad的代码描述,其实就是对mutex封装,关闭了拷贝构造和赋值函数

#include <iostream>
#include <thread>
#include <list>
#include <mutex>
int ticketCount = 100;

std::mutex mtx;//互斥锁


void sellTicket(int window) {

	while (ticketCount > 0) {
		
		{
			std::lock_guard<std::mutex> lock(mtx);
                        if(ticketCount >0){
                             std::cout << "窗口" << window << "销售" << ticketCount << std::endl;
			     ticketCount--;
                        }
			std::this_thread::sleep_for(std::chrono::milliseconds(50));
		
		}
		
	}

}//end



int main() {

	std::list<std::thread> tlist;
	
	for (int i = 0; i < 3; i++) {
		tlist.push_back(std::thread(sellTicket,i));
	}

	for (std::thread & t : tlist) {
		t.join();
	}

	system("pause");
	return 0;
}

上面的图片中我们知道lock_gurad 的拷贝构造函数被关闭了,所以当我们遇到函数调用需要拷贝构造lock_guard的时候,就有障碍了,这个时候可以用unique_lock

unique_lock 转移指针,支持带右值得拷贝赋值,支持参数传递拷贝构造的,他的左值的拷贝构造也是被关闭了 看下图

posted @ 2022-12-12 16:01  Hello_Bugs  阅读(124)  评论(0编辑  收藏  举报