System.Threading.Barrier多线程屏障类,分界线
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 对象测量时间间隔,同时观察取消标记。 |
新建控制台应用程序BarrierDemo:
using System;
using System.Threading;
using System.Threading.Tasks;
namespace BarrierDemo
{
class Program
{
static void Main(string[] args)
{
//参考文档
//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)之后,之后再一起坐车出去,到达指定地点后一起行动或者各自行动。
*/
try
{
BarrierSample();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
Console.ReadLine();
}
static void BarrierSample()
{
int count = 0;
// Create a barrier with three participants
// Provide a post-phase action that will print out certain information
// And the third time through, it will throw an exception
Barrier barrier = new Barrier(3, (b) =>
{
Console.WriteLine("Post-Phase action: count={0}, phase={1}", count, b.CurrentPhaseNumber);
if (b.CurrentPhaseNumber == 2)
{
//throw new Exception("D'oh!");
Console.WriteLine("D'oh!");
}
});
Console.WriteLine($"参与者个数:【{barrier.ParticipantCount}】");
// Nope -- changed my mind. Let's make it five participants.
barrier.AddParticipants(2);
Console.WriteLine($"增加2个参与者,当前参与者个数:【{barrier.ParticipantCount}】");
// Nope -- let's settle on four participants.
barrier.RemoveParticipant();
Console.WriteLine($"减少1个参与者,当前参与者个数:【{barrier.ParticipantCount}】");
// This is the logic run by all participants
Action action = () =>
{
Interlocked.Increment(ref count);
barrier.SignalAndWait(); // during the post-phase action, count should be 4 and phase should be 0
Interlocked.Increment(ref count);
barrier.SignalAndWait(); // during the post-phase action, count should be 8 and phase should be 1
// The third time, SignalAndWait() will throw an exception and all participants will see it
Interlocked.Increment(ref count);
try
{
barrier.SignalAndWait();
}
catch (BarrierPostPhaseException bppe)
{
Console.WriteLine("Caught BarrierPostPhaseException: {0}", bppe.Message);
}
// The fourth time should be hunky-dory
Interlocked.Increment(ref count);
barrier.SignalAndWait(); // during the post-phase action, count should be 16 and phase should be 3
};
// Now launch 4 parallel actions to serve as 4 participants
Parallel.Invoke(action, action, action, action);
// This (5 participants) would cause an exception:
// Parallel.Invoke(action, action, action, action, action);
// "System.InvalidOperationException: The number of threads using the barrier
// exceeded the total number of registered participants."
// It's good form to Dispose() a barrier when you're done with it.
barrier.Dispose();
}
}
}