当前位置: 首页 > news >正文

c++介绍线程的屏障 八

 c++ 20中引入了latch和barrier,提供了一种简单的同步机制,来协调多个线程

线程屏障提供了一个计数器,每个参与任务的线程完成自己的任务后,计数器减1.而需要同步的线程,屏障计数器可以阻塞,等待计数器为0时,继续执行后面的代码。

latch为一次性计数,当计数为0时就不能重复使用了。而barrirer为多个阶段的计数。

下面模拟一个比赛:发令枪响起,选手开跑,全部选手到达终点后统计成绩。

#include<array>
#include<vector>
#include<thread>
#include<iostream>
#include<mutex>
#include<algorithm>
#include<sstream>
#include<iomanip>
#include<semaphore>
#include<random>
#include<syncstream>
#include<latch>
using namespace std;
struct Runner
{
	string name;
	int time{ 0 };
	void run(latch& start, latch& end)
	{
		//等待发令枪响
		start.wait();
		auto start_time = chrono::system_clock::now();
		mt19937 eng{ random_device{}() };
		uniform_int_distribution<unsigned int>uniform_int_distribution{ 0,2000 };
		this_thread::sleep_for(chrono::microseconds(9600000 + uniform_int_distribution(eng)));
		auto end_time = chrono::system_clock::now();
		time = chrono::duration_cast<chrono::milliseconds>(end_time - start_time).count();
		//跑完了
		end.count_down(1);//计数器减1
	}
	bool operator<(const Runner& other)const { return time < other.time; }
};

int main()
{
	vector<Runner> runners = { Runner{"张三"},Runner{"李四"},Runner{"王五"},Runner{"赵六"},Runner{"钱七"}};
	const int runner_counter = runners.size();
	latch start(1);
	latch finish(runner_counter);

	vector<thread>threads;
	for (int i = 0; i < runner_counter; i++)
	{
		threads.emplace_back(&Runner::run,&runners[i],ref(start),ref(finish));
	}
	cout << "发令枪响起" << endl;

	start.count_down();//阻塞等待计数器减为0

	//等待所有选手跑完
	finish.wait();//阻塞等待计数器减为0
	cout << "比赛结果:\n=============================\n";
	sort(runners.begin(), runners.end());
	for (auto& runner : runners)
	{
		cout << runner.name << ":" << float(runner.time) / 1000 << "秒" << endl;
	}
	for (auto& t : threads)
	{
		t.join();
	}
	return 0;
}

打印结果

 下面来看下barrier,与latch不同时,当barrier计数器为0时,开始新的一轮计时。

barrier是一个类模版,模版参数是一个可调用对象,每次计数器为0时会调用该函数。构造函数传递一个初始计数值。arrive将计数器减去传入的n.wait等待本阶段计数器到达为0. arrive_and_wait是arrive和wait一起使用,arrive_and_drop除了将本阶段计数减去n,还将下一阶段 初始计数值减去n. 

下面模拟一个幸存者游戏,每轮淘汰不符合条件的玩家,一共进行五轮游戏。

#include<array>
#include<vector>
#include<thread>
#include<iostream>
#include<mutex>
#include<algorithm>
#include<sstream>
#include<iomanip>
#include<semaphore>
#include<syncstream>
#include<numeric>
#include<future>
#include<random>
#include<barrier>
using namespace std;
class Participant
{
public:
	string name;
	Participant(string name) :name(name) {}
	template<typename BarrierType>
	void run(BarrierType& finish)
	{
		mt19937 eng(random_device{}());
		uniform_int_distribution<unsigned int>uniform_dist(1000, 2000);
		for (int i = 0; i < 5; i++)
		{
			auto rnd = uniform_dist(eng);
			this_thread::sleep_for(chrono::milliseconds(rnd));
			alive = rnd % 3;
			if (alive)
			{
				finish.arrive_and_wait();//阻塞等待计数器 减到0
			}
			else
			{
				finish.arrive_and_drop();//当前减1并将下一轮减1
				break;
			}
		}
	}
	bool is_alive()const
	{
		return alive;
	}
private:
	bool alive = true;
};
int main()
{
	vector<Participant>participant = { Participant{"张三"},Participant{"李四"},Participant{"王五"},Participant{"赵六"},Participant{"钱七"}};
	const int participant_count = participant.size();
	int round = 0;
	auto on_complete = [&participant, &round]() noexcept {
		round++;
		cout << "第" << round << "轮幸存者:" << endl;
		int count = 0;
		for (auto& p : participant)
		{
			if (p.is_alive())
			{
				cout << p.name << " ";
				count++;
			}
		}
		cout << endl;
		if (count == 0)
			cout << "无" << endl;
	};
	barrier finish(participant_count,on_complete);//计数器减为0时回调on_complete函数
	vector<thread>threads;
	for (auto& p : participant)
	{
		threads.emplace_back([&p, &finish]() 
		{
			p.run(finish);
		});
	}
	for (auto& thread : threads)
		thread.join();
	return 0;
}

相关文章:

  • nnUNet V2修改网络——全配置替换MultiResBlock模块
  • 密码学笔记
  • springboot 自动装配原理
  • 用户模块——redis工具类
  • 04 | 初始化 fastgo 项目仓库
  • tcp/ip协议中网络层协议的主要特点,tcp/ip协议中网络层都有哪些协议?
  • c# 2025/3/12 周三
  • MyBatis 的核心配置文件是干什么的? 它的结构是怎样的? 哪些是必须配置的,哪些是可选的?
  • AI重构SEO关键词布局
  • TA学习之路——1.4 MVP矩阵运算
  • 安全左移动赋能:灵脉IAST交互式应用安全测试平台
  • Python的日志
  • HarmonyOS学习第19天:感知世界的 “超能力”,HarmonyOS 传感器揭秘
  • ChātGPT开发“SolidWorks工具箱”,可建海量3D模型库,能一键画图、批量赋属性、自动出图,效率提高10倍
  • 浅拷贝和深拷贝AI
  • 复试数据库原理总结
  • Unity3D网格简化与LOD技术详解
  • Linux 内核文件读取与内存映射管理机制的理解心得
  • 「 机器人 」扑翼飞行器通过总气动力控制四自由度运动方法
  • LLM:了解大语言模型
  • 秦洪看盘|上市公司业绩“排雷”近尾声,A股下行压力趋缓
  • 言短意长|新能源领军者密集捐赠母校
  • 外交部回应涉长江和记出售巴拿马运河港口交易:望有关各方审慎行事,充分沟通
  • 李勇已任内蒙古乌兰察布市委副书记,曾在中央编办任职
  • 民调显示特朗普执政百日支持率为80年来美历任总统最低
  • 王庆成:儒家、墨家和洪秀全的“上帝”