Barrier:屏障,障碍,分界线
使多个任务能够采用并行方式依据某种算法在多个阶段中协同工作。
多个线程各自执行完毕,合并一起后再往下执行其他事件
在Barrier之前,若干个thread各自执行,然后到了Barrier的时候停下,等待规定数目的所有的其他线程到达这个Barrier,之后再一起通过这个Barrier各自干自己的事情。
比如:大家从各自的工位到会议室集合,待人数都到齐(Barrier)之后,开始会议并讨论问题。
Task.WaitAll(Task1,Task2,Task3,....);
DoSomething();
注解
通过一系列阶段共同合作的一组任务,其中每个阶段都在每个阶段到达, Barrier 并隐式等待所有其他阶段到达。 相同的 Barrier 可用于多个阶段。
属性
CurrentPhaseNumber | 获取屏障的当前阶段的编号。 |
ParticipantCount | 获取屏障中参与者的总数。 |
ParticipantsRemaining | 获取屏障中尚未在当前阶段发出信号的参与者的数量。 |
方法
AddParticipant() | 通知 Barrier,告知其将会有另一个参与者。 |
AddParticipants(Int32) | 通知 Barrier,告知其将会有多个其他参与者。 |
Dispose() | 释放 Barrier 类的当前实例所使用的所有资源。 |
RemoveParticipant() | 通知 Barrier,告知其将会减少一个参与者。 |
RemoveParticipants(Int32) | 通知 Barrier,告知其将会减少一些参与者。 |
SignalAndWait() | 发出参与者已达到屏障并等待所有其他参与者也达到屏障。 |
SignalAndWait(CancellationToken) | 发出参与者已达到屏障的信号,并等待所有其他参与者达到屏障,同时观察取消标记。 |
SignalAndWait(Int32) | 发出参与者已达到屏障的信号,并等待所有其他参与者也达到屏障,同时使用 32 位带符号整数测量超时。 |
SignalAndWait(Int32, CancellationToken) | 发出参与者已达到屏障的信号,并等待所有其他参与者也达到屏障,使用 32 位带符号整数测量超时,同时观察取消标记。 |
SignalAndWait(TimeSpan) | 发出参与者已达到屏障的信号,并等待所有其他参与者也达到屏障,同时使用 TimeSpan 对象测量时间间隔。 |
SignalAndWait(TimeSpan, CancellationToken) | 发出参与者已达到屏障的信号,并等待所有其他参与者也达到屏障,使用 TimeSpan 对象测量时间间隔,同时观察取消标记。 |
//参考文档
https://docs.microsoft.com/zh-cn/dotnet/api/system.threading.barrier?view=netcore-3.1
//源代码:
//https://referencesource.microsoft.com/#System/sys/system/threading/Barrier.cs,6ff43d8403f8e835
//Barrier:屏障,障碍,分界线
//使多个任务能够采用并行方式依据某种算法在多个阶段中协同工作。
/*
* 主要是用作集合线程,然后再一起往下执行。
* 再具体一点,在Barrier之前,若干个thread各自执行,然后到了Barrier的时候停下,等待规定数目的所有的其他线程到达这个Barrier,之后再一起通过这个Barrier各自干自己的事情。
* 集体活动的过程,大家从各自的家里到学校集合,待人数都到齐(Barrier)之后,之后再一起坐车出去,到达指定地点后一起行动或者各自行动。
*/
新建控制台应用程序BarrierDemo:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace BarrierDemo
{
class Program
{
static void Main(string[] args)
{
Console.SetWindowSize(100, 30);
Barrier barrier = new Barrier(4, b =>
{
Console.WriteLine($"每个阶段完成【所有参与者都达到屏障,SignalAndWait()之后】之后执行。参与者总数:{b.ParticipantCount},当前阶段:{b.CurrentPhaseNumber}");
});
Console.WriteLine($"初始参与者个数:【{barrier.ParticipantCount}】");
barrier.AddParticipants(2);
Console.WriteLine($"增加2个参与者,当前参与者个数:【{barrier.ParticipantCount}】");
barrier.RemoveParticipant();
Console.WriteLine($"减少1个参与者,当前参与者个数:【{barrier.ParticipantCount}】");
int count = 0;
Action action = new Action(() =>
{
Interlocked.Increment(ref count);
//用信号通知参与者已达到屏障,并等待所有其他参与者到达屏障。所有人每到达一次屏障,则当前阶段就加一
barrier.SignalAndWait();
Console.WriteLine($"当前线程编号:【{Thread.CurrentThread.ManagedThreadId}】计数器:【{count}】参与者总数:{barrier.ParticipantCount},当前阶段:{barrier.CurrentPhaseNumber}");
Interlocked.Increment(ref count);
barrier.SignalAndWait();
Console.WriteLine($"当前线程编号:【{Thread.CurrentThread.ManagedThreadId}】计数器:【{count}】参与者总数:{barrier.ParticipantCount},当前阶段:{barrier.CurrentPhaseNumber}");
Interlocked.Increment(ref count);
try
{
barrier.SignalAndWait();
Console.WriteLine($"当前线程编号:【{Thread.CurrentThread.ManagedThreadId}】计数器:【{count}】参与者总数:{barrier.ParticipantCount},当前阶段:{barrier.CurrentPhaseNumber}");
}
catch (BarrierPostPhaseException bppe)
{
Console.WriteLine("Caught BarrierPostPhaseException: {0}", bppe.Message);
}
Interlocked.Increment(ref count);
barrier.SignalAndWait();
Console.WriteLine($"当前线程编号:【{Thread.CurrentThread.ManagedThreadId}】计数器:【{count}】参与者总数:{barrier.ParticipantCount},当前阶段:{barrier.CurrentPhaseNumber}");
});
//注意:为了确保所有的参与者都已执行,因此:并行的委托个数 一定是参与者总数【barrier.ParticipantCount】
Action[] actionCollection = new Action[barrier.ParticipantCount];
for (int i = 0; i < actionCollection.Length; i++)
{
actionCollection[i] = action;
}
Parallel.Invoke(actionCollection);
barrier.Dispose();
Console.ReadLine();
}
}
}