1. 程式人生 > 其它 ><二>執行緒間互斥-mutex互斥鎖和lock_guard

<二>執行緒間互斥-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

#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);
			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 轉移指標,支援帶右值得拷貝賦值,支援引數傳遞拷貝構造的,他的左值的拷貝構造也是被關閉了 看下圖