最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

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

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

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

先來(lái)看下面這段簡(jiǎn)單的代碼:

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中運(yùn)行函數(shù)print,每個(gè)線程對(duì)g_num進(jìn)行加加一次,最后加出來(lái)的g_num的值應(yīng)該是10,那么我們現(xiàn)在來(lái)看結(jié)果:

我們看到運(yùn)行結(jié)果,為什么打印結(jié)果最后,按理來(lái)說(shuō)兩個(gè)線程各加五次,最后結(jié)果應(yīng)該是10呀,怎么會(huì)是9呢?

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

atomic_int g_num = 0; //將g_num設(shè)置為原子操作數(shù)
//atomic<int> g_num = 0;這個(gè)和上面是一樣的 下面這行是模板化之后的
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è)置為原子操作數(shù)之后,在++階段就不會(huì)被線程調(diào)度機(jī)制給打斷,我們來(lái)看運(yùn)行結(jié)果:

運(yùn)行結(jié)果是我所期望的但是中間那塊又出了一點(diǎn)小狀況連著打著兩個(gè)4,兩個(gè)6,這種情況該怎么辦呢?

下面就該說(shuō)道我們的互斥鎖了:

互斥鎖:

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

來(lái)看下面代碼:

int g_num = 0;
std::mutex mtx;  //創(chuàng)建鎖對(duì)象
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;
}

我們來(lái)看運(yùn)行結(jié)果:符合我們最初的預(yù)期。

 打開官方文檔,可以看到

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

std::mutex::try_lock         

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

 try_lock字面意思就是說(shuō)嘗試上鎖,如果上鎖成功,返回true,上鎖失敗則返回false,但是如果上鎖失敗,他還是會(huì)接著往下運(yùn)行,不會(huì)像lock哪運(yùn)被阻塞在上鎖那塊,所以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且沒(méi)把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;
}

我們來(lái)看運(yùn)行結(jié)果:

 unlock of  unowned  mutex,這玩意思就是說(shuō)你在給個(gè)沒(méi)上鎖的互斥鎖解鎖,所以報(bào)這錯(cuò)誤,因此try_lock擱在普通語(yǔ)句中,會(huì)有很大的問(wèn)題,現(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失敗時(shí)為false 前面加了!,所以失敗時(shí)為true 然后打印嘗試加鎖
		{                    //然后再次嘗試加鎖,只有加鎖成功了,才能出這個(gè)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;
}

我們來(lái)看運(yùn)行結(jié)果:

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

條件變量:condition_variable

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

這三個(gè)函數(shù)呢,通過(guò)一個(gè)小實(shí)驗(yàn)來(lái)實(shí)現(xiàn),通過(guò)多線程分別打印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相當(dāng)于線程中的智能制造 自動(dòng)解鎖,不需要再unlock
	int i = 0;
	while (i < n)
	{
		while (isReady != 0) 
		{
			cv.wait(lock);//互斥鎖和信號(hào)量一起使用  wait參數(shù)為鎖對(duì)象
		}
		cout << "A" ;
		isReady = 1;
		++i;
		std::this_thread::sleep_for(std::chrono::microseconds(100));
		cv.notify_all(); //當(dāng)isReady等于0時(shí)print_B 和 print_C 處于阻塞狀態(tài)  
          //該函數(shù)就是喚醒所有等待的函數(shù),然后通過(guò)isReady來(lái)進(jìn)行判斷要進(jìn)行那個(gè)函數(shù)的運(yùn)行
	}
}
void print_B()
{
	std::unique_lock<mutex> lock(mtx);  //unique_lock相當(dāng)于線程中的智能制造 自動(dòng)解鎖,不需要再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相當(dāng)于線程中的智能制造 自動(dòng)解鎖,不需要再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;
}

上面代碼解析:

運(yùn)行結(jié)果:

我們可以看到上述代碼最后喚醒其他線程使用的是notify_all()函數(shù),notify_all()函數(shù)作用就是環(huán)球其他阻塞的函數(shù),然后因?yàn)閕sready這個(gè)數(shù)的存在,所以就會(huì)選擇合適的線程來(lái)進(jìn)行執(zhí)行,如果我們使用notify_one()呢,先來(lái)說(shuō)下notify_one()函數(shù)的作用是什么。notify_one()函數(shù)是喚醒其他線程(隨機(jī)喚醒,這道題中不適合,因?yàn)槿绻蛴⊥闍之后喚醒了C線程那么就會(huì)一直阻塞在那塊)

我們?cè)囈幌耼otify_one()函數(shù),可以發(fā)現(xiàn)這玩意確實(shí)會(huì)堵塞在那塊:

總結(jié)

本篇文章就到這里了,希望能夠給你帶來(lái)幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容! 

相關(guān)文章

  • C/C++指針介紹與使用詳解

    C/C++指針介紹與使用詳解

    不知從何時(shí)起對(duì)你一眼萬(wàn)年,從此,每一天被賦予了特別的意義。時(shí)隔多年,依然揮之不去是你------指針?。?!本篇中幾乎數(shù)據(jù)類型只用了int,但是float、double等也是可以的
    2022-08-08
  • 深入理解atoi()與itoa()函數(shù)的用法

    深入理解atoi()與itoa()函數(shù)的用法

    本篇文章是對(duì)atoi()與itoa()函數(shù)的用法進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下
    2013-05-05
  • C++實(shí)現(xiàn)基于靜態(tài)數(shù)組的順序表

    C++實(shí)現(xiàn)基于靜態(tài)數(shù)組的順序表

    這篇文章主要介紹了C++實(shí)現(xiàn)基于靜態(tài)數(shù)組的順序表,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-05-05
  • C語(yǔ)言字符串常用處理函數(shù)小結(jié)

    C語(yǔ)言字符串常用處理函數(shù)小結(jié)

    C語(yǔ)言中有很多內(nèi)置的字符串處理函數(shù),這些函數(shù)都在<string.h>頭文件中聲明,本文給大家介紹C語(yǔ)言字符串常用處理函數(shù)小結(jié),感興趣的朋友一起看看吧
    2023-11-11
  • 淺談const變量賦值報(bào)錯(cuò)分析

    淺談const變量賦值報(bào)錯(cuò)分析

    在類中 只有靜態(tài)變量能賦值 如果你不賦值 編譯器會(huì)認(rèn)為你這個(gè)變量根本沒(méi)用 不能被修改 又沒(méi)有初始值 兩個(gè)辦法 在構(gòu)造函數(shù)的初始化列表賦值 或者在const前面加一個(gè)static
    2015-07-07
  • opencv3/C++實(shí)現(xiàn)光流點(diǎn)追蹤

    opencv3/C++實(shí)現(xiàn)光流點(diǎn)追蹤

    今天小編就為大家分享一篇opencv3/C++實(shí)現(xiàn)光流點(diǎn)追蹤,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2019-12-12
  • C語(yǔ)言中進(jìn)程信號(hào)集的相關(guān)操作函數(shù)詳解

    C語(yǔ)言中進(jìn)程信號(hào)集的相關(guān)操作函數(shù)詳解

    這篇文章主要介紹了C語(yǔ)言中進(jìn)程信號(hào)集的相關(guān)操作函數(shù)詳解,包括sigismember函數(shù)和sigfillset函數(shù)以及sigemptyset函數(shù)的用法,需要的朋友可以參考下
    2015-09-09
  • C語(yǔ)言野指針及如何規(guī)避詳解

    C語(yǔ)言野指針及如何規(guī)避詳解

    這篇文章主要為大家介紹了C語(yǔ)言野指針及如何規(guī)避詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-09-09
  • exit和atexit的區(qū)別詳細(xì)解析

    exit和atexit的區(qū)別詳細(xì)解析

    以下是對(duì)exit與atexit的區(qū)別進(jìn)行了詳細(xì)的分析介紹,需要的朋友可以過(guò)來(lái)參考下
    2013-09-09
  • C語(yǔ)言實(shí)現(xiàn)字符轉(zhuǎn)unix時(shí)間戳的簡(jiǎn)單實(shí)例

    C語(yǔ)言實(shí)現(xiàn)字符轉(zhuǎn)unix時(shí)間戳的簡(jiǎn)單實(shí)例

    下面小編就為大家?guī)?lái)一篇C語(yǔ)言實(shí)現(xiàn)字符轉(zhuǎn)unix時(shí)間戳的簡(jiǎn)單實(shí)例。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2016-06-06

最新評(píng)論

临朐县| 枞阳县| 元谋县| 沁源县| 桐乡市| 蓝田县| 旌德县| 仁化县| 图木舒克市| 崇阳县| 通海县| 新巴尔虎右旗| 溧水县| 博爱县| 桂林市| 信宜市| 澄迈县| 清新县| 炎陵县| 泰顺县| 台中县| 定安县| 乌拉特前旗| 灵丘县| 福贡县| 揭阳市| 昭觉县| 德清县| 云霄县| 乌什县| 长岛县| 梁河县| 古浪县| 洞口县| 大兴区| 永川市| 冷水江市| 宜君县| 白朗县| 巨鹿县| 泰宁县|