溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

C++怎么實(shí)現(xiàn)兩個(gè)線程交替打印

發(fā)布時(shí)間:2022-08-26 11:46:19 來源:億速云 閱讀:206 作者:iii 欄目:開發(fā)技術(shù)

這篇“C++怎么實(shí)現(xiàn)兩個(gè)線程交替打印”文章的知識(shí)點(diǎn)大部分人都不太理解,所以小編給大家總結(jié)了以下內(nèi)容,內(nèi)容詳細(xì),步驟清晰,具有一定的借鑒價(jià)值,希望大家閱讀完這篇文章能有所收獲,下面我們一起來看看這篇“C++怎么實(shí)現(xiàn)兩個(gè)線程交替打印”文章吧。

首先簡(jiǎn)單搭一個(gè)框架,讓兩個(gè)線程先嘗試實(shí)現(xiàn)交替打印。

//實(shí)現(xiàn)兩個(gè)線程交替打印
#include <iostream>
#include <thread>
using namespace std;
int main(void)
{
	int n = 100;
	int i = 0;
	//創(chuàng)建兩個(gè)線程
	thread t1([&n, &i](){
		while (i < n)
		{
			cout << i << " ";
			i++;
		}
	});
	thread t2([&n, &i]() {
		while (i < n)
		{
			cout << i << " ";
			i++;
		}
	});
	if (t1.joinable())
	{
		t1.join();
	}
	if (t2.joinable())
	{
		t2.join();
	}
	return 0;
}

為了讓我們更加清楚是哪個(gè)線程打印了,我們需要獲取線程的ID。

#include <iostream>
#include <thread>
using namespace std;
int main(void)
{
	int n = 100;
	int i = 0;
	//創(chuàng)建兩個(gè)線程
	thread t1([&n, &i](){
		while (i < n)
		{
			cout << this_thread::get_id()  << ": " << i << endl;
			i++;
		}
	});
	thread t2([&n, &i]() {
		while (i < n)
		{
			cout << this_thread::get_id() << ": " << i << endl;
			i++;
		}
	});
	if (t1.joinable())
	{
		t1.join();
	}
	if (t2.joinable())
	{
		t2.join();
	}
	return 0;
}

C++怎么實(shí)現(xiàn)兩個(gè)線程交替打印

這顯然沒有完成兩個(gè)線程交替打印的目的,甚至數(shù)據(jù)的打印都非常地亂。這是因?yàn)閕是臨界資源,多個(gè)線程爭(zhēng)搶訪問臨界資源可能會(huì)造成數(shù)據(jù)二義,線程是不安全的,需要保證任意時(shí)刻只有一個(gè)線程能夠訪問臨界資源。

所以創(chuàng)建一個(gè)互斥量,并在臨界區(qū)合適的地方加鎖和解鎖。由于線程的執(zhí)行函數(shù)我使用了lambda表達(dá)式,為了讓兩個(gè)線程使用的是同一把鎖,把鎖創(chuàng)建在了main函數(shù)內(nèi),并在lambda表達(dá)式內(nèi)使用了引用捕捉。

#include <iostream>
#include <thread>
#include <mutex>
using namespace std;
int main(void)
{
	int n = 100;
	int i = 0;
	mutex mtx;
	//創(chuàng)建兩個(gè)線程
	thread t1([&n, &i, &mtx](){
		while (i < n)
		{
			mtx.lock();
			cout << this_thread::get_id()  << ": " << i << endl;
			i++;
			mtx.unlock();
		}
	});
	thread t2([&n, &i, &mtx]() {
		while (i < n)
		{
			mtx.lock();
			cout << this_thread::get_id() << ": " << i << endl;
			i++;
			mtx.unlock();
		}
	});
	if (t1.joinable())
	{
		t1.join();
	}
	if (t2.joinable())
	{
		t2.join();
	}
	return 0;
}

在C++中,一般不直接操作鎖,而是由類去管理鎖。

//第一個(gè)管理鎖的類
template <class Mutex> class lock_guard;
//第二個(gè)管理鎖的類
template <class Mutex> class unique_lock;

lock_guar類,只有構(gòu)造和析構(gòu)函數(shù)。一般用于加鎖和解鎖,這里進(jìn)行簡(jiǎn)單的模擬:

//注意:為了使得加鎖和解鎖的是同一把鎖
//需要使用引用
template <class Lock>
class LockGuard
{
public:
	LockGuard(Lock &lck)
		:_lock(lck)
	{
		_lock.lock();
	}
	~LockGuard()
	{
		_lock.unlock();
	}
private:
	Lock &_lock;
};

unique_lock的成員方法就不僅僅是析構(gòu)函數(shù)和構(gòu)造函數(shù)。詳見文檔unique_lock介紹和使用。

這里將鎖交給unique_lock類的對(duì)象進(jìn)行管理。

int main(void)
{
	int n = 100;
	int i = 0;
	mutex mtx;
	//創(chuàng)建兩個(gè)線程
	thread t1([&n, &i, &mtx, &cv, &flag](){
		while (i < n)
		{
			unique_lock<mutex> LockManage(mtx);
			cout << this_thread::get_id()  << ": " << i << endl;
			i++;
		}
	});
	thread t2([&n, &i, &mtx, &cv, &flag]() {
		while (i < n)
		{
			unique_lock<mutex> LockManage(mtx);
			cout << this_thread::get_id() << ": " << i << endl;
			i++;
		}
	});
	if (t1.joinable())
	{
		t1.join();
	}
	if (t2.joinable())
	{
		t2.join();
	}
	return 0;
}

C++怎么實(shí)現(xiàn)兩個(gè)線程交替打印

線程是安全了,但如果其中一個(gè)線程競(jìng)爭(zhēng)鎖的能力比較強(qiáng),那么可能會(huì)出現(xiàn)上面這種情況。

需要控制:一個(gè)線程執(zhí)行一次后,如果再次去執(zhí)行就不準(zhǔn)許了,同時(shí)可以喚醒另一個(gè)進(jìn)程去執(zhí)行,如此循環(huán)往復(fù)達(dá)到交替打印的目的。所以可以增加一個(gè)條件變量,讓某個(gè)線程在該條件變量下的阻塞隊(duì)列等待。

C++庫中線程在條件變量下的等待函數(shù)第一個(gè)參數(shù)注意是管理鎖的類對(duì)象

int main(void)
{
	int n = 100;
	int i = 0;
	mutex mtx;
	condition_variable cv;
	bool flag = false;
	//創(chuàng)建兩個(gè)線程
	thread t1([&n, &i, &mtx, &cv, &flag](){
		while (i < n)
		{
			unique_lock<mutex> LockManage(mtx);
			//!flag為真,那么獲取后不會(huì)阻塞,優(yōu)先運(yùn)行
			cv.wait(LockManage, [&flag]() {return !flag; });
			cout << this_thread::get_id()  << ": " << i << endl;
			i++;
		}
	});
	thread t2([&n, &i, &mtx, &cv, &flag]() {
		while (i < n)
		{
			unique_lock<mutex> LockManage(mtx);
			//flag為假,競(jìng)爭(zhēng)到鎖后,由于條件不滿足,阻塞
			cv.wait(LockManage, [&flag]() {return flag; });
			cout << this_thread::get_id() << ": " << i << endl;
			i++;
		}
	});
	if (t1.joinable())
	{
		t1.join();
	}
	if (t2.joinable())
	{
		t2.join();
	}
	return 0;
}

這里flag以及l(fā)ambda表達(dá)式的增加是非常巧妙的。flag的初始化值為false,讓線程t2在[&flag]() {return false; }下等待,那么t2線程就會(huì)先執(zhí)行。

C++怎么實(shí)現(xiàn)兩個(gè)線程交替打印

線程t1競(jìng)爭(zhēng)到了鎖,但是由于不滿足條件,會(huì)繼續(xù)等待,所以就出現(xiàn)了上面的情況。

需要一個(gè)線程喚醒另一個(gè)線程之前,將flag的值進(jìn)行修改。

int main(void)
{
	int n = 100;
	int i = 0;
	mutex mtx;
	condition_variable cv;
	bool flag = false;
	//創(chuàng)建兩個(gè)線程
	thread t1([&n, &i, &mtx, &cv, &flag](){
		while (i < n)
		{
			unique_lock<mutex> LockManage(mtx);
			//!flag為真,那么獲取后不會(huì)阻塞,優(yōu)先運(yùn)行
			cv.wait(LockManage, [&flag]() {return !flag; });
			cout << this_thread::get_id()  << ": " << i << endl;
			i++;
			flag = true;
			cv.notify_one();
		}
	});
	thread t2([&n, &i, &mtx, &cv, &flag]() {
		while (i < n)
		{
			unique_lock<mutex> LockManage(mtx);
			//flag為假,競(jìng)爭(zhēng)到鎖后,由于條件不滿足,阻塞
			cv.wait(LockManage, [&flag]() {return flag; });
			cout << this_thread::get_id() << ": " << i << endl;
			i++;
			flag = false;
			cv.notify_one();
		}
	});
	if (t1.joinable())
	{
		t1.join();
	}
	if (t2.joinable())
	{
		t2.join();
	}
	return 0;
}

最終,實(shí)現(xiàn)了兩個(gè)線程交替打?。ㄒ粋€(gè)線程打印奇數(shù)、一個(gè)線程打印偶數(shù))

以上就是關(guān)于“C++怎么實(shí)現(xiàn)兩個(gè)線程交替打印”這篇文章的內(nèi)容,相信大家都有了一定的了解,希望小編分享的內(nèi)容對(duì)大家有幫助,若想了解更多相關(guān)的知識(shí)內(nèi)容,請(qǐng)關(guān)注億速云行業(yè)資訊頻道。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

c++
AI