zoukankan      html  css  js  c++  java
  • Barrier实现并发同步

    Barrier,中文被译为屏障。在C#中,可以用来实现多任务在多阶段中协同工作。通俗来讲,就是多个线程在执行到某个被共同指定步骤(即Barrier.SignalAndWait())的时候,就像遇到了屏障一样,必须等待其他还未执行到该步骤的线程。如果每个线程都执行到了该步骤,则大家又继续执行各自的逻辑。

    Barrier对象可防止并行操作中的各个任务在所有任务到达屏障前继续执行。 如果并行操作分阶段执行,且每个阶段需要在任务之间进行同步,此对象就很有用。

    在实例化Barrier对象的时候,还可以指定一个Action委托,该委托会在所有任务到达屏障后立即执行,接着各个任务又继续执行它们各自的逻辑。该Action委托只与Barrier对象关联,无论有多少个任务,只要它们都达到屏障后,该Action委托就会执行一次。

    Barrier.SignalAndWait()该方法会通知Barrier对象,一个线程已经到达了屏障,需要等待其他还未到达屏障的线程。

    1、普通使用方式

    代码如下所示:

            //指定3个并行任务,当三个并行任务到达屏障后,就执行预先定义的Action委托
            //如果有第4个任务执行了SignalAndWait()方法,就会报错,因为当前Barrier对象只指定了3个可以并行的任务数量
            static Barrier barrier=new Barrier(3, it =>
            {
                Console.WriteLine($"Barrier委托 开始执行");
                Console.WriteLine($"Barrier委托 获取Barrier.CurrentPhaseNumber={barrier.CurrentPhaseNumber}");
                Thread.Sleep(2000);
                Console.WriteLine($"Barrier委托 执行完毕");
            });
    
            static void WorkOnBarrierOne(string threadName)
            {
                Console.WriteLine($"{threadName} 开始执行");
                Console.WriteLine($"{threadName} 获取Barrier.CurrentPhaseNumber={barrier.CurrentPhaseNumber}");
                Console.WriteLine($"{threadName} 到达屏障");
                barrier.SignalAndWait();
                Console.WriteLine($"{threadName} 再次获取Barrier.CurrentPhaseNumber={barrier.CurrentPhaseNumber}");
                Console.WriteLine($"{threadName} 执行完毕");
            }
    
            static void WorkOnBarrierTwo(string threadName) {
                Console.WriteLine($"{threadName} 开始执行");
                Console.WriteLine($"{threadName} 获取Barrier.CurrentPhaseNumber={barrier.CurrentPhaseNumber}");
                Thread.Sleep(1000);
                Console.WriteLine($"{threadName} 到达屏障");
                barrier.SignalAndWait();
                Console.WriteLine($"{threadName} 再次获取Barrier.CurrentPhaseNumber={barrier.CurrentPhaseNumber}");
                Console.WriteLine($"{threadName} 执行完毕");
            }

    Main方法中的代码:

                Thread t1 = new Thread(() => WorkOnBarrierOne("线程1"));
                Thread t2 = new Thread(() => WorkOnBarrierTwo("线程2"));
                t1.Start();
                t2.Start();
    
                Console.WriteLine($"主线程 到达屏障");
                barrier.SignalAndWait();
                Console.WriteLine($"主线程 获取Barrier.CurrentPhaseNumber={barrier.CurrentPhaseNumber}");
                Console.WriteLine($"主线程 执行完毕");

    结果:

     从结果中可以看出,只有指定的所有线程到达屏障(Barrier.SignalAndWait()方法处)之后,在Barrier对象中预先定义的Action委托就会执行,Action委托执行完毕之后,Barrier的CurrentPhaseNumber就会自增1,即表示当前阶段数量自增1。

    Barrier可以执行很多阶段,可以将Barrier.SignalAndWait()方法放在一个循环代码中。

    2、超时等待

    可以在Barrier.SignalAndWait(int millisecondsTimeout)中使用超时等待结果。如果等待超时,则返回false,未超时,则返回true。

    在超时等待之后,需要移除一个参与者,否则其他的线程就会一直阻塞等待。

    因为超时等待后,就像一个人先跑了,而其他人到达屏障后并不知道有人先跑掉,他们会一直等待,因为只有人数在聚齐的情况下,他们才会又各自散去。

    而此时,将先跑的人数减少,则剩下的就有机会聚齐。

    Main代码如下所示:

                Thread t1 = new Thread(() => WorkOnBarrierOne("线程1"));
                Thread t2 = new Thread(() => WorkOnBarrierTwo("线程2"));
                t1.Start();
                t2.Start();
    
                Console.WriteLine($"主线程 到达屏障");
                //等待超时后,Barrier.SignalAndWait()会返回false,没有超时,会返回true
                if (!barrier.SignalAndWait(1000))
                {
                    Console.WriteLine($"主线程 到达屏障后等待超时");
                    //等待超时后,需要移除一个参与者,否则其他的线程就会一直等待
                    //因为超时等待后,就像一个人先跑了,而其他人到达屏障后并不知道有人先跑掉,他们会一直等待,因为只有人数在聚齐的情况下,他们才会又各自散去
                    //而此时,将先跑的人数减少,则剩下的就有机会聚齐
                    barrier.RemoveParticipant();
                }
    
                Console.WriteLine($"主线程 获取Barrier.CurrentPhaseNumber={barrier.CurrentPhaseNumber}");
                Console.WriteLine($"主线程 执行完毕");

    超时结果如下所示:

    参考文献:https://docs.microsoft.com/zh-cn/dotnet/standard/threading/barrier

  • 相关阅读:
    mac 10.15.7 修改PATH
    oc 属性类型一般用法
    ubuntu解压zip文件名乱码
    telnet 退出
    docker 根据容器创建镜像
    mac android adb device 没有显示设备
    Yii2 查看所有的别名 alias
    Yii2 App Advanced 添加 .gitignore
    ubuntu 18.04 搜狗突然就提示乱码
    An error occured while deploying the file. This probably means that the app contains ARM native code and your Genymotion device cannot run ARM instructions. You should either build your native code to
  • 原文地址:https://www.cnblogs.com/williamwsj/p/13858474.html
Copyright © 2011-2022 走看看