欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C++多線程互斥鎖和條件變量的詳解

 更新時間:2022年03月18日 10:34:59   作者:神廚小福貴!  
這篇文章主要為大家詳細介紹了C++多線程互斥鎖和條件變量,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助

我們了解互斥量和條件變量之前,我們先來看一下為什么要有互斥量和條件變量這兩個東西,了解為什么有這兩東西之后,理解起來后面的東西就簡單很多了?。?!

先來看下面這段簡單的代碼:

int g_num = 0;
void print(int id)
{
	for (int i = 0; i < 5; i++)
	{
		++g_num;
		cout << "id = " << id << "==>" << g_num << endl;
		std::this_thread::sleep_for(std::chrono::seconds(1));
	}
}
int main()
{
	thread tha(print, 0);
	thread thb(print, 1);
	tha.join();
	thb.join();
	return 0;
}

上述代碼功能大致就是在線程tha和thb中運行函數(shù)print,每個線程對g_num進行加加一次,最后加出來的g_num的值應該是10,那么我們現(xiàn)在來看結果:

我們看到運行結果,為什么打印結果最后,按理來說兩個線程各加五次,最后結果應該是10呀,怎么會是9呢?

 如上圖所示,是因為++這個運算符不是原子操作(不會被線程調度機制打斷的操作),我們可以將g_num設置為原子數(shù),改為atomic_int g_num = 0;

atomic_int g_num = 0; //將g_num設置為原子操作數(shù)
//atomic<int> g_num = 0;這個和上面是一樣的 下面這行是模板化之后的
void print(int id)
{
	for (int i = 0; i < 5; i++)
	{
		++g_num;
		cout << "id = " << id << "==>" << g_num << endl;
		std::this_thread::sleep_for(std::chrono::seconds(1));
	}
}
int main()
{
	thread tha(print, 0);
	thread thb(print, 1);
	tha.join();
	thb.join();
	return 0;
}

將g_num設置為原子操作數(shù)之后,在++階段就不會被線程調度機制給打斷,我們來看運行結果:

運行結果是我所期望的但是中間那塊又出了一點小狀況連著打著兩個4,兩個6,這種情況該怎么辦呢?

下面就該說道我們的互斥鎖了:

互斥鎖:

在上述代碼中我們使用了共享資源----->全局量g_num,兩個線程同時對g_num進行++操作,為了保護共享資源,在線程里也有這么一把鎖——互斥鎖(mutex),互斥鎖是一種簡單的加鎖的方法來控制對共享資源的訪問,互斥鎖只有兩種狀態(tài),即上鎖( lock )和解鎖( unlock )。

來看下面代碼:

int g_num = 0;
std::mutex mtx;  //創(chuàng)建鎖對象
void print(int id)
{
	for (int i = 0; i < 5; i++)
	{
		mtx.lock();  //上鎖
		++g_num;
		cout << "id = " << id << "==>" << g_num << endl;
		mtx.unlock(); //解鎖
		std::this_thread::sleep_for(std::chrono::microseconds(500));
	}
}
int main()
{
	thread tha(print, 0);
	thread thb(print, 1);
	tha.join();
	thb.join();
	return 0;
}

我們來看運行結果:符合我們最初的預期。

 打開官方文檔,可以看到

創(chuàng)建鎖對象只有這個方法,拷貝構造被刪除了 。

std::mutex::try_lock         

對于互斥鎖的lock和unlock我們都很熟悉了,下面來說一下std::mutex::try_lock這個成員函數(shù)!

 try_lock字面意思就是說嘗試上鎖,如果上鎖成功,返回true,上鎖失敗則返回false,但是如果上鎖失敗,他還是會接著往下運行,不會像lock哪運被阻塞在上鎖那塊,所以try_lock必須得在循環(huán)中使用:

int g_num = 0;
std::mutex mtx;
void print(int id)
{
	for (int i = 0; i < 5; i++)
	{
		mtx.try_lock();  //代碼只是將lock換成了try_lock且沒把try_lock扔在循環(huán)中執(zhí)行
		++g_num;
		cout << "id = " << id << "==>" << g_num << endl;
		mtx.unlock();
		std::this_thread::sleep_for(std::chrono::microseconds(500));
	}
}
int main()
{
	thread tha(print, 0);
	thread thb(print, 1);
	tha.join();
	thb.join();
	return 0;
}

我們來看運行結果:

 unlock of  unowned  mutex,這玩意思就是說你在給個沒上鎖的互斥鎖解鎖,所以報這錯誤,因此try_lock擱在普通語句中,會有很大的問題,現(xiàn)命我們演示一下將這玩意放到循環(huán)中去弄一邊:

int g_num = 0;
std::mutex mtx;
void print(int id)
{
	for (int i = 0; i < 5; i++)
	{
		while (!mtx.try_lock())  //try_lock失敗時為false 前面加了!,所以失敗時為true 然后打印嘗試加鎖
		{                    //然后再次嘗試加鎖,只有加鎖成功了,才能出這個while循環(huán)
			cout << "try  lock" << endl;
		}	
		++g_num;
		cout << "id = " << id << "==>" << g_num << endl;
		mtx.unlock();
		std::this_thread::sleep_for(std::chrono::microseconds(500));
	}
}
int main()
{
	thread tha(print, 0);
	thread thb(print, 1);
	tha.join();
	thb.join();
	return 0;
}

我們來看運行結果:

 運行結果符合我們的預期,但是try_lock這個函數(shù)有個不好處是太損耗資源了,當它加鎖失敗時,一直嘗試加鎖一直嘗試加鎖,損耗CPU資源。

條件變量:condition_variable

框住這三個函數(shù)較為重要,下面著重來說下面這三個函數(shù): 這里順便說一下,下面代碼將會是條件變量和互斥鎖的結合使用,至于為什么要將互斥鎖和條件變量一起使用,原因就是互斥鎖狀態(tài)太單一了,而條件變量允許阻塞,接收信號量等剛好彌補了互斥鎖的缺陷所以這些一起使用?。?!

這三個函數(shù)呢,通過一個小實驗來實現(xiàn),通過多線程分別打印123一直到100:

std::mutex mtx;
std::condition_variable cv;
int isReady = 0;
const int n = 100;
void print_A()
{
	std::unique_lock<mutex> lock(mtx);  //unique_lock相當于線程中的智能制造 自動解鎖,不需要再unlock
	int i = 0;
	while (i < n)
	{
		while (isReady != 0) 
		{
			cv.wait(lock);//互斥鎖和信號量一起使用  wait參數(shù)為鎖對象
		}
		cout << "A" ;
		isReady = 1;
		++i;
		std::this_thread::sleep_for(std::chrono::microseconds(100));
		cv.notify_all(); //當isReady等于0時print_B 和 print_C 處于阻塞狀態(tài)  
          //該函數(shù)就是喚醒所有等待的函數(shù),然后通過isReady來進行判斷要進行那個函數(shù)的運行
	}
}
void print_B()
{
	std::unique_lock<mutex> lock(mtx);  //unique_lock相當于線程中的智能制造 自動解鎖,不需要再unlock
	int i = 0;
	while (i < n)
	{
		while (isReady != 1)
		{
			cv.wait(lock);
		}
		cout << "B" ;
		isReady = 2;
		++i;
		std::this_thread::sleep_for(std::chrono::microseconds(100));
		cv.notify_all();
	}
}
void print_C()
{
	std::unique_lock<mutex> lock(mtx);  //unique_lock相當于線程中的智能制造 自動解鎖,不需要再unlock
	int i = 0;
	while (i < n)
	{
		while (isReady != 2)
		{
			cv.wait(lock);
		}
		cout << "C" ;
		isReady = 0;
		++i;
		std::this_thread::sleep_for(std::chrono::microseconds(100));
		cv.notify_all();
	}
}
int main()
{
	thread tha(print_A);
	thread thb(print_B);
	thread thc(print_C);
	tha.join();
	thb.join();
	thc.join();
	return 0;
}

上面代碼解析:

運行結果:

我們可以看到上述代碼最后喚醒其他線程使用的是notify_all()函數(shù),notify_all()函數(shù)作用就是環(huán)球其他阻塞的函數(shù),然后因為isready這個數(shù)的存在,所以就會選擇合適的線程來進行執(zhí)行,如果我們使用notify_one()呢,先來說下notify_one()函數(shù)的作用是什么。notify_one()函數(shù)是喚醒其他線程(隨機喚醒,這道題中不適合,因為如果打印完A之后喚醒了C線程那么就會一直阻塞在那塊)

我們試一下notify_one()函數(shù),可以發(fā)現(xiàn)這玩意確實會堵塞在那塊:

總結

本篇文章就到這里了,希望能夠給你帶來幫助,也希望您能夠多多關注腳本之家的更多內容! 

相關文章

  • 初學C++之自定義類型名簡化詳解

    初學C++之自定義類型名簡化詳解

    下面小編就為就大家?guī)硪黄鯇WC++之自定義類型名簡化詳解。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2016-09-09
  • linux c語言操作數(shù)據(jù)庫(連接sqlite數(shù)據(jù)庫)

    linux c語言操作數(shù)據(jù)庫(連接sqlite數(shù)據(jù)庫)

    linux下c語言操作sqlite數(shù)據(jù)庫實例方法,大家參考使用吧
    2013-12-12
  • C++二維數(shù)組中的查找算法示例

    C++二維數(shù)組中的查找算法示例

    這篇文章主要介紹了C++二維數(shù)組中的查找算法,結合實例形式分析了C++二維數(shù)組進行查找的原理與具體實現(xiàn)技巧,需要的朋友可以參考下
    2017-05-05
  • QT編寫地圖實現(xiàn)離線輪廓圖的示例代碼

    QT編寫地圖實現(xiàn)離線輪廓圖的示例代碼

    這篇文章主要介紹了在利用QT編寫地圖時常常需要用到的離線輪廓圖,離線輪廓圖使用起來比線輪廓圖麻煩一點,需要自己繪制。感興趣的小伙伴可以學習一下
    2021-12-12
  • C語言實現(xiàn)二叉樹的示例詳解

    C語言實現(xiàn)二叉樹的示例詳解

    這篇文章主要為大家詳細介紹了C語言中二叉樹的算法實現(xiàn)以及二叉樹的遍歷算法與應用,文中的示例代碼講解詳細,感興趣的小伙伴可以了解一下
    2023-06-06
  • C語言連接并操作Sedna XML數(shù)據(jù)庫的方法

    C語言連接并操作Sedna XML數(shù)據(jù)庫的方法

    這篇文章主要介紹了C語言連接并操作Sedna XML數(shù)據(jù)庫的方法,實例分析了C語言操作XML文件的相關技巧,需要的朋友可以參考下
    2015-06-06
  • C++使用TinyXML解析XML

    C++使用TinyXML解析XML

    本文詳細講解了C++使用TinyXML解析XML的方法,文中通過示例代碼介紹的非常詳細。對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-12-12
  • 詳解C語言通過遞歸與非遞歸實現(xiàn)蛇形矩陣

    詳解C語言通過遞歸與非遞歸實現(xiàn)蛇形矩陣

    蛇形矩陣(Snake matrix)是矩陣的一種,常被應用在編程題目與數(shù)學數(shù)列中,需要提取每條斜線里最小的數(shù)字,本篇文章將會通過遞歸和非遞歸來分別實現(xiàn)蛇形矩陣
    2022-02-02
  • C語言實現(xiàn)簡單酒店管理系統(tǒng)

    C語言實現(xiàn)簡單酒店管理系統(tǒng)

    這篇文章主要為大家詳細介紹了C語言實現(xiàn)簡單酒店管理系統(tǒng),文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-03-03
  • C++ 的類型轉換詳解

    C++ 的類型轉換詳解

    本篇文章是對C++ 類型轉換的詳細介紹,需要的朋友參考下,小編覺得這篇文章寫的不錯,希望能夠給你帶來幫助
    2021-11-11

最新評論