日本免费高清视频-国产福利视频导航-黄色在线播放国产-天天操天天操天天操天天操|www.shdianci.com

學無先后,達者為師

網站首頁 編程語言 正文

C++在多線程中使用condition_variable實現wait_C 語言

作者:君子以閱川 ? 更新時間: 2022-11-10 編程語言

前言

有這樣的需求

一個線程需要等待另一個線程執行完畢之后它才會繼續向下執行,這該如何實現? condition_variable類中實現了wait方法

wait()

  • 可以接受兩個參數,其中第一個參數是鎖對象,第二個參數是lambda表達式,其中的lambda表達式的返回值要是bool類型
  • 也可接受一個參數,僅僅接受鎖對象
#include<iostream>
#include<mutex>
#include<list>
#include<thread>
using namespace std;
class Obj
{
private:
	list<int> myList;
	condition_variable var;
	mutex tex;
public:
	bool popFromList(int & comb)
	{
		if (!myList.empty()) {
			unique_lock<mutex> cur(tex);
			if (!myList.empty())
			{
				comb = myList.front();
				myList.pop_front();
				return true;
			}
		}
		return false;
	}
	void inToList()
	{
		for (int i = 0; i < 100; i++)
		{
			unique_lock<mutex> cur(tex);
			myList.push_back(i);
			cout << this_thread::get_id() << "正在向list中添加數據>; " << i << endl;
			var.notify_one();
		}
	}
	void outFromList()
	{
		while(true)
		{
			unique_lock<mutex> cur(tex);
			var.wait(cur, [this] {
				if (!myList.empty())
					return true;
				return false;
				});
			int comb = myList.front();
			myList.pop_front();
			cout << this_thread::get_id() << "正在取出數據>: " << comb << endl;
		}
	}
};
int main()
{
	Obj obj;
	thread thread1(&Obj::outFromList, &obj);
	thread thread2(&Obj::inToList, &obj);
	thread1.join();
	thread2.join();
	cout << "這里是主線程" << endl;
}

線程1執行到wait函數時,會執行lambda表達式

返回值為false時,這個線程就會將鎖打開,將該線程壓入到棧中,執行下一個線程 下一個線程執行完畢之后執行notify_one后就會返回到該線程,繼續執行lambda表達式

返回值為true時就嘗試獲得鎖

獲得鎖后繼續執行下面的語句

沒有獲得鎖就繼續卡在wait等待獲取到鎖

返回值為false時,繼續將鎖打開,線程壓入棧,執行下一個線程

返回值為true時,線程繼續執行

運行結果可能是一個線程執行完畢另一個線程再執行

這不就是順序執行嗎?

其實并不是這樣的

notify_one()

喚醒wait()函數,當前所再的線程嘗試獲得鎖

某個線程執行完notify_one函數后,會返回到另一個線程中的wait函數處,并將其"喚醒",讓其繼續執行,自己的線程和wait線程都嘗試獲得鎖來進行下一步執行

不是順序執行的解釋

  • 當wait函數后面有很多語句要執行,但是再此之前wait所在的線程函數中就已經將鎖進行釋放了,那么notify_one的“喚醒”就不在生效,兩個線程都嘗試獲得鎖,但是wait所在的線程有很多語句要執行,耗時高,那么很有可能notify_one所在的線程就再次獲得了鎖,進行下一步操作。
  • 這樣就不一定是順序執行的宏觀表現了
#include<iostream>
#include<mutex>
#include<list>
#include<thread>
using namespace std;
class Obj
{
private:
	list<int> myList;
	condition_variable var;
	mutex tex;
public:
	bool popFromList(int & comb)
	{
		if (!myList.empty()) {
			unique_lock<mutex> cur(tex);
			if (!myList.empty())
			{
				comb = myList.front();
				myList.pop_front();
				return true;
			}
		}
		return false;
	}
	void inToList()
	{
		for (int i = 0; i < 1000; i++)
		{
			cout << this_thread::get_id() << "正在向list中添加數據>; " << i << endl;
			unique_lock<mutex> cur(tex);
			myList.push_back(i);
			var.notify_one();
		}
	}
	void outFromList()
	{
		while(true)
		{
			unique_lock<mutex> cur(tex);
			var.wait(cur, [this] {
				if (!myList.empty())
					return true;
				return false;
				});
			int comb = myList.front();
			myList.pop_front();
			cur.unlock();
			cout << this_thread::get_id() << "正在取出數據>: " << comb << endl;
			chrono::seconds tim(2);
			this_thread::sleep_for(tim);
			cout <<this_thread::get_id() <<  "睡眠兩秒后執行" << endl;
		}
	}
};
int main()
{
	Obj obj;
	thread thread1(&Obj::outFromList, &obj);
	thread thread2(&Obj::inToList, &obj);
	thread1.join();
	thread2.join();
	cout << "這里是主線程" << endl;
}

如圖所示,在notify_one線程執行835次循環后,wait所在的線程才獲得了鎖,繼續執行

在此之前的所有notify_one的喚醒操作都是無效的。

然后在notify_one線程執行完畢之后,wait再次獲得了鎖,繼續向下執行

notify_all()

顧名思義,是“喚醒”所有的wait函數線程,但是并不是都一起運行,因為他們要進行鎖的請求,僅僅只能由一把鎖存在,只有獲得鎖并且lambda表達式返回結果為true的線程才能繼續執行

原文鏈接:https://blog.csdn.net/m0_56104219/article/details/126911671

欄目分類
最近更新