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();
        }
    }
}
 

运行效果如图:

System.Threading.Barrier多线程屏障类,分界线