亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

c++多線程為何要使用條件變量詳解

 更新時(shí)間:2021年06月04日 11:32:27   作者:發(fā)如雪-ty  
多線程是多任務(wù)處理的一種特殊形式,下面這篇文章主要給大家介紹了關(guān)于c++多線程為何要使用條件變量的相關(guān)資料,需要的朋友可以參考下

先看示例1:

#include <iostream>
#include <windows.h>
#include <mutex>
#include<deque>
#include <thread>
using namespace std;


int nmax = 20;
std::deque<int> m_que;
std::mutex mymutex;


//生產(chǎn)者

void producterex()
{
	int i = 1;
	while (i<nmax)
	{
		//休眠一秒鐘
		std::this_thread::sleep_for(std::chrono::seconds(1));

		std::unique_lock<mutex> lcx(mymutex);
		m_que.push_back(i);
		cout << "producted:" << i << endl;
		lcx.unlock();
		i++;
	}

	cout << "product thread exit\n";
}

//消費(fèi)者
void consumerex()
{
	int i = 0;
	while (1)
	{
		std::unique_lock<mutex> lcx(mymutex);
		if (!m_que.empty())
		{
			int i = m_que.back();
			m_que.pop_back();
			cout << "consumed:" << i << endl;
			lcx.unlock();
			i++;
			if (i == nmax)
			{
				
				break;
			}
		}
		else
		{
			lcx.unlock();
		}
		
		
	}

	cout << "consumerex thread exit\n";
}

void main()
{
	std::thread t1(producterex);
	std::thread t2(consumerex);

	t1.detach();
	cout << "hello";
	t2.detach();
	cout << " world!\n";
	getchar();
	system("pause");
}

結(jié)果:

可見cpu使用率非常高。高的原因主要在消費(fèi)者線程中,因?yàn)楫?dāng)隊(duì)列為空的時(shí)候它也要執(zhí)行,做了過(guò)多的無(wú)用功導(dǎo)致CPU占有率過(guò)高,所以下面對(duì)進(jìn)行一個(gè)改造讓其在空的時(shí)候等待200毫秒,相當(dāng)于增大了輪詢間隔周期,應(yīng)該能降低CPU的占用率。

在這里就貼上消費(fèi)者的線程,因?yàn)槠渌亩家粯印?/p>

//消費(fèi)者
void consumerex()
{
	int i = 0;
	while (1)
	{
		std::unique_lock<mutex> lcx(mymutex);
		if (!m_que.empty())
		{
			int i = m_que.back();
			m_que.pop_back();
			cout << "consumed:" << i << endl;
			lcx.unlock();
			i++;
			if (i == nmax)
			{
				
				break;
			}
		}
		else
		{
			lcx.unlock();
			std::this_thread::sleep_for(std::chrono::milliseconds(200));
		}
		
		
	}

	cout << "consumerex thread exit\n";
}

結(jié)果:

可見CPU占用率一下子下降了。

這里就有一個(gè)困難了,那就是如何確定休眠的時(shí)間間隔(即輪詢間隔周期),如果間隔太短會(huì)過(guò)多占用CPU資源,如果間隔太長(zhǎng)會(huì)因無(wú)法及時(shí)響應(yīng)造成延誤。

這就引入了條件變量來(lái)解決該問題:條件變量使用“通知—喚醒”模型,生產(chǎn)者生產(chǎn)出一個(gè)數(shù)據(jù)后通知消費(fèi)者使用,消費(fèi)者在未接到通知前處于休眠狀態(tài)節(jié)約CPU資源;當(dāng)消費(fèi)者收到通知后,趕緊從休眠狀態(tài)被喚醒來(lái)處理數(shù)據(jù),使用了事件驅(qū)動(dòng)模型,在保證不誤事兒的情況下盡可能減少無(wú)用功降低對(duì)資源的消耗。

condition_variable介紹
在C++11中,我們可以使用條件變量(condition_variable)實(shí)現(xiàn)多個(gè)線程間的同步操作;當(dāng)條件不滿足時(shí),相關(guān)線程被一直阻塞,直到某種條件出現(xiàn),這些線程才會(huì)被喚醒。

成員函數(shù)如下:

條件變量是利用線程間共享的全局變量進(jìn)行同步的一種機(jī)制,主要包括兩個(gè)動(dòng)作:

a.一個(gè)線程因等待"條件變量的條件成立"而掛起;

b.另外一個(gè)線程使"條件成立",給出信號(hào),從而喚醒被等待的線程。

為了防止競(jìng)爭(zhēng),條件變量的使用總是和一個(gè)互斥鎖結(jié)合在一起;通常情況下這個(gè)鎖是std::mutex,并且管理這個(gè)鎖 只能是 std::unique_lockstd::mutex RAII模板類。

上面提到的兩個(gè)步驟,分別是使用以下兩個(gè)方法實(shí)現(xiàn):

1.等待條件成立使用的是condition_variable類成員wait 、wait_for 或 wait_until。

2.給出信號(hào)使用的是condition_variable類成員notify_one或者notify_all函數(shù)。

以上兩個(gè)類型的wait函數(shù)都在會(huì)阻塞時(shí),自動(dòng)釋放鎖權(quán)限,即調(diào)用unique_lock的成員函數(shù)unlock(),以便其他線程能有機(jī)會(huì)獲得鎖。這就是條件變量只能和unique_lock一起使用的原因,否則當(dāng)前線程一直占有鎖,線程被阻塞。

虛假喚醒

在正常情況下,wait類型函數(shù)返回時(shí)要不是因?yàn)楸粏拘眩皇且驗(yàn)槌瑫r(shí)才返回,但是在==實(shí)際中發(fā)現(xiàn),因此操作系統(tǒng)的原因,wait類型在不滿足條件時(shí),它也會(huì)返回,這就導(dǎo)致了虛假喚醒。==因此,我們一般都是使用帶有謂詞參數(shù)的wait函數(shù),因?yàn)檫@種(xxx, Predicate pred )類型的函數(shù)等價(jià)于:

while (!pred()) //while循環(huán),解決了虛假喚醒的問題
{
    wait(lock);
}

原因說(shuō)明如下:

假設(shè)系統(tǒng)不存在虛假喚醒的時(shí),代碼形式如下:

if (不滿足xxx條件)
{
    //沒有虛假喚醒,wait函數(shù)可以一直等待,直到被喚醒或者超時(shí),沒有問題。
    //但實(shí)際中卻存在虛假喚醒,導(dǎo)致假設(shè)不成立,wait不會(huì)繼續(xù)等待,跳出if語(yǔ)句,
    //提前執(zhí)行其他代碼,流程異常
    wait();  
}


//其他代碼
...

正確的使用方式,使用while語(yǔ)句解決:

while (!(xxx條件) )
{
    //虛假喚醒發(fā)生,由于while循環(huán),再次檢查條件是否滿足,
    //否則繼續(xù)等待,解決虛假喚醒
    wait();  
}
//其他代碼
....

下面看一個(gè)使用條件變量的情況:

#include <iostream>
#include <windows.h>
#include <mutex>
#include<deque>
#include <thread>
#include<condition_variable>
using namespace std;


int nmax = 10;
std::deque<int> m_que;
std::mutex mymutex;

condition_variable mycv;

//生產(chǎn)者

void producterex()
{
	int i = 1;
	while (i<nmax)
	{
		//休眠一秒鐘
		std::this_thread::sleep_for(std::chrono::seconds(1));

		std::unique_lock<mutex> lcx(mymutex);
		m_que.push_back(i);
		cout << "producted:" << i << endl;
		lcx.unlock();

		mycv.notify_one();
		i++;
	}

	cout << "product thread exit\n";
}

//消費(fèi)者
bool m_bflag = false;
void consumerex()
{
	int i = 0;
	bool m_bexit = false;
	while (!m_bexit)
	{
		std::unique_lock<mutex> lcx(mymutex);

		while (m_que.empty())
		{
			//避免虛假喚醒
			mycv.wait(lcx);
			if (m_bflag)
			{
				cout << "consumerex thread exit\n";
				m_bexit = true;
				break;

			}
		}
	
		
		if (m_bexit)
		{
			break;
		}
			
		int i = m_que.back();
		m_que.pop_back();
		lcx.unlock();
		cout << "consumed:" << i << endl;		
	}

	cout << "consumerex thread exit\n";
}

void main()
{
	std::thread t1(producterex);
	std::thread t2(consumerex);

	t1.detach();
	cout << "hello";
	t2.detach();
	cout << " world!\n";
	mycv.notify_one();
	Sleep(15000);
	m_que.push_back(100);
	mycv.notify_one();
	Sleep(3000);
	m_bflag = true;
	mycv.notify_one();//通知線程退出
	getchar();
	system("pause");
}

結(jié)果:

還可以將mycv.wait(lcx);換一種寫法,wait()的第二個(gè)參數(shù)可以傳入一個(gè)函數(shù)表示檢查條件,這里使用lambda函數(shù)最為簡(jiǎn)單,如果這個(gè)函數(shù)返回的是true,wait()函數(shù)不會(huì)阻塞會(huì)直接返回,如果這個(gè)函數(shù)返回的是false,wait()函數(shù)就會(huì)阻塞著等待喚醒,如果被偽喚醒,會(huì)繼續(xù)判斷函數(shù)返回值。代碼示例如下:

#include <iostream>
#include <windows.h>
#include <mutex>
#include<deque>
#include <thread>
#include<condition_variable>
using namespace std;


int nmax = 10;
std::deque<int> m_que;
std::mutex mymutex;

condition_variable mycv;

//生產(chǎn)者

void producterex()
{
	int i = 1;
	while (i<nmax)
	{
		//休眠一秒鐘
		std::this_thread::sleep_for(std::chrono::seconds(1));

		std::unique_lock<mutex> lcx(mymutex);
		m_que.push_back(i);
		cout << "producted:" << i << endl;
		lcx.unlock();

		mycv.notify_one();
		i++;
	}

	cout << "product thread exit\n";
}

//消費(fèi)者
bool m_bflag = false;
void consumerex()
{
	int i = 0;

	while (1)
	{
		std::unique_lock<mutex> lcx(mymutex);

		mycv.wait(lcx, [](){

			//返回false就繼續(xù)等待
			return !m_que.empty();
		});
				
		if (m_bflag)
		{
			break;
		}
		int i = m_que.back();
		m_que.pop_back();
		lcx.unlock();
		cout << "consumed:" << i << endl;
	
		
	}

	cout << "consumerex thread exit\n";
}

void main()
{
	std::thread t1(producterex);
	std::thread t2(consumerex);

	t1.detach();
	cout << "hello";
	t2.detach();
	cout << " world!\n";
	mycv.notify_one();
	Sleep(15000);
	m_que.push_back(100);
	mycv.notify_one();
	Sleep(3000);
	m_bflag = true;
	m_que.push_back(-1);
	mycv.notify_one();//通知線程退出
	getchar();
	system("pause");
}

總結(jié)

到此這篇關(guān)于c++多線程為何要使用條件變量的文章就介紹到這了,更多相關(guān)c++多線程條件變量?jī)?nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • C語(yǔ)言實(shí)現(xiàn)簡(jiǎn)單猜拳小游戲

    C語(yǔ)言實(shí)現(xiàn)簡(jiǎn)單猜拳小游戲

    這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言實(shí)現(xiàn)簡(jiǎn)單猜拳小游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-03-03
  • 減少OpenCV讀取高分辨率圖像的時(shí)間示例

    減少OpenCV讀取高分辨率圖像的時(shí)間示例

    今天小編就為大家分享一篇減少OpenCV讀取高分辨率圖像的時(shí)間示例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2019-12-12
  • C++枚舉類型用法總結(jié)(枚舉字符常量代替常量)

    C++枚舉類型用法總結(jié)(枚舉字符常量代替常量)

    這篇文章主要介紹了C++枚舉類型用法總結(jié)(枚舉字符常量代替常量),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-12-12
  • sizeof()的簡(jiǎn)單介紹

    sizeof()的簡(jiǎn)單介紹

    sizeof操作符以字節(jié)形式給出了其操作數(shù)的存儲(chǔ)大小
    2013-04-04
  • 使用C++描繪心形

    使用C++描繪心形

    本文給大家分享的是一個(gè)使用c++繪制心形的代碼,雖然情人節(jié)已經(jīng)過(guò)去了,但是只要有心,天天都是情人節(jié)~~哈哈,讓那些說(shuō)程序猿都是木頭的人去死吧。
    2015-03-03
  • boost.asio框架系列之調(diào)度器io_service

    boost.asio框架系列之調(diào)度器io_service

    這篇文章介紹了boost.asio框架系列之調(diào)度器io_service,對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2022-06-06
  • C語(yǔ)言示例講解switch分支語(yǔ)句的用法

    C語(yǔ)言示例講解switch分支語(yǔ)句的用法

    這篇文章主要為大家介紹了switch語(yǔ)句,switch語(yǔ)句是我們常見會(huì)用到的結(jié)構(gòu),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-06-06
  • C/C++中g(shù)etline函數(shù)案例總結(jié)

    C/C++中g(shù)etline函數(shù)案例總結(jié)

    這篇文章主要介紹了C/C++中g(shù)etline函數(shù)案例總結(jié),本篇文章通過(guò)簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下
    2021-09-09
  • C++ tuple元組的基本用法(總結(jié))

    C++ tuple元組的基本用法(總結(jié))

    這篇文章主要介紹了C++ tuple元組的基本用法(總結(jié)),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-07-07
  • C語(yǔ)言實(shí)現(xiàn)三子棋的步驟和代碼詳解

    C語(yǔ)言實(shí)現(xiàn)三子棋的步驟和代碼詳解

    這篇文章主要介紹了C語(yǔ)言實(shí)現(xiàn)三子棋的步驟和代碼詳解,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-12-12

最新評(píng)論