C++怎么实现两个线程交替打印

首先简单搭一个框架,让两个线程先尝试实现交替打印

//实现两个线程交替打印#include <iostream>#include <thread>using namespace std;int main(void){	int n = 100;	int i = 0;	//创建两个线程	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;}

为了让我们更加清楚是哪个线程打印了,我们需要获取线程的ID。

#include <iostream>#include <thread>using namespace std;int main(void){	int n = 100;	int i = 0;	//创建两个线程	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++怎么实现两个线程交替打印

这显然没有完成两个线程交替打印的目的,甚至数据的打印都非常地乱。这是因为i是临界资源,多个线程争抢访问临界资源可能会造成数据二义,线程是不安全的,需要保证任意时刻只有一个线程能够访问临界资源。

所以创建一个互斥量,并在临界区合适的地方加锁和解锁。由于线程的执行函数我使用了lambda表达式,为了让两个线程使用的是同一把锁,把锁创建在了main函数内,并在lambda表达式内使用了引用捕捉。

#include <iostream>#include <thread>#include <mutex>using namespace std;int main(void){	int n = 100;	int i = 0;	mutex mtx;	//创建两个线程	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++中,一般不直接操作锁,而是由类去管理锁。

//名列前茅个管理锁的类template <class Mutex> class lock_guard;//第二个管理锁的类template <class Mutex> class unique_lock;

lock_guar类,只有构造和析构函数。一般用于加锁和解锁,这里进行简单的模拟:

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

unique_lock的成员方法就不仅仅是析构函数和构造函数。详见文档unique_lock介绍和使用。

这里将锁交给unique_lock类的对象进行管理。

int main(void){	int n = 100;	int i = 0;	mutex mtx;	//创建两个线程	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++怎么实现两个线程交替打印

线程是安全了,但如果其中一个线程竞争锁的能力比较强,那么可能会出现上面这种情况。

需要控制:一个线程执行一次后,如果再次去执行就不准许了,同时可以唤醒另一个进程去执行,如此循环往复达到交替打印的目的。所以可以增加一个条件变量,让某个线程在该条件变量下的阻塞队列等待。

C++库中线程在条件变量下的等待函数名列前茅个参数注意是管理锁的类对象

int main(void){	int n = 100;	int i = 0;	mutex mtx;	condition_variable cv;	bool flag = false;	//创建两个线程	thread t1([&n, &i, &mtx, &cv, &flag](){		while (i < n)		{			unique_lock<mutex> LockManage(mtx);			//!flag为真,那么获取后不会阻塞,优先运行			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为假,竞争到锁后,由于条件不满足,阻塞			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以及lambda表达式的增加是非常巧妙的。flag的初始化值为false,让线程t2在[&flag]() {return false; }下等待,那么t2线程就会先执行。

C++怎么实现两个线程交替打印

线程t1竞争到了锁,但是由于不满足条件,会继续等待,所以就出现了上面的情况。

需要一个线程唤醒另一个线程之前,将flag的值进行修改。

int main(void){	int n = 100;	int i = 0;	mutex mtx;	condition_variable cv;	bool flag = false;	//创建两个线程	thread t1([&n, &i, &mtx, &cv, &flag](){		while (i < n)		{			unique_lock<mutex> LockManage(mtx);			//!flag为真,那么获取后不会阻塞,优先运行			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为假,竞争到锁后,由于条件不满足,阻塞			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;}

最终,实现了两个线程交替打印(一个线程打印奇数、一个线程打印偶数)

以上就是关于“C++怎么实现两个线程交替打印”这篇文章的内容,相信大家都有了一定的了解,希望小编分享的内容对大家有帮助,若想了解更多相关的知识内容,请关注亿速云行业资讯频道。

文章标题:C++怎么实现两个线程交替打印,发布者:亿速云,转载请注明出处:https://worktile.com/kb/p/20984

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
亿速云的头像亿速云
上一篇 2022年8月27日 下午5:00
下一篇 2022年8月27日 下午5:01

相关推荐

  • 2024年9款优质CRM系统全方位解析

    文章介绍的工具有:纷享销客、Zoho CRM、八百客、红圈通、简道云、简信CRM、Salesforce、HubSpot CRM、Apptivo。 在选择合适的CRM系统时,许多企业面临着功能繁多、选择困难的痛点。对于中小企业来说,找到一个既能提高客户关系管理效率,又能适应业务扩展的CRM系统尤为重要…

    2024年7月25日
    2000
  • 数据库权限关系图表是什么

    数据库权限关系图表是一种以图表形式展示数据库权限分配和管理的工具。它可以有效地帮助我们理解和管理数据库中的各种权限关系。数据库权限关系图表主要包含以下几个部分:数据对象、用户(或用户组)、权限类型、权限级别、权限状态等。其中,数据对象是权限关系图表中的核心元素,它代表了数据库中的各种数据资源,如表、…

    2024年7月22日
    200
  • 诚信数据库是什么意思

    诚信数据库是一种收集、存储和管理个人或组织诚信信息的系统。它是一种用于评估和管理个人或组织行为的工具,通常由政府、商业组织或者非营利组织进行运营。诚信数据库的主要功能包括:1、评估个人或组织的诚信状况;2、提供决策支持;3、预防和控制风险;4、促进社会信用体系建设。 在这四大功能中,评估个人或组织的…

    2024年7月22日
    400
  • 数据库期末关系代数是什么

    关系代数是一种对关系进行操作的代数系统,是关系模型的数学基础,主要用于从关系数据库中检索数据。其操作包括选择、投影、并集、差集、笛卡尔积、连接、除法等。其中,选择操作是对关系中的元组进行筛选,只保留满足某一条件的元组;投影操作则是从关系中选择出一部分属性构造一个新的关系。 一、选择操作 选择操作是关…

    2024年7月22日
    700
  • mysql建立数据库用什么命令

    在MySQL中,我们使用"CREATE DATABASE"命令来创建数据库。这是一个非常简单且基础的命令,其语法为:CREATE DATABASE 数据库名。在这个命令中,“CREATE DATABASE”是固定的,而“数据库名”则是你要创建的数据库的名称,可以自己设定。例如,如…

    2024年7月22日
    500
注册PingCode 在线客服
站长微信
站长微信
电话联系

400-800-1024

工作日9:30-21:00在线

分享本页
返回顶部