如何在.net 3.5中实现.net 4中Barrier类的功能

本文关键字:net Barrier 功能 实现 | 更新日期: 2023-09-27 18:03:59

由于某些原因,我必须坚持使用。net 3.5,并且我需要。net 4中Barrier类的功能。我有一堆线程在做一些工作,我想让它们互相等待,直到所有的工作都完成。当一切都完成后,我希望他们以同样的方式一次又一次地做这项工作。被c# 4.0中的Barrier和c# 3.0中的WaitHandle之间的线程差异所鼓舞?我决定用AutoResetEvent和WaitHandle类来实现Barrier功能。虽然我遇到了一个问题,我的代码:

class Program
{
    const int numOfThreads = 3;
    static AutoResetEvent[] barrier = new AutoResetEvent[numOfThreads];
    static Random random = new Random(System.DateTime.Now.Millisecond);
    static void barriers2(object barrierObj)
    {
        AutoResetEvent[] barrierLocal = (AutoResetEvent[])barrierObj;
        string name = Thread.CurrentThread.Name;
        for (int i = 0; i < 10; i++)
        {
            int sleepTime = random.Next(2000, 10000);
            System.Console.Out.WriteLine("Thread {0} at the 'barrier' will sleep for {1}.", name, sleepTime);
            Thread.Sleep(sleepTime);
            System.Console.Out.WriteLine("Thread {0} at the 'barrier' with time {1}.", name, sleepTime);
            int currentId = Convert.ToInt32(name);
            //for(int z = 0; z < numOfThreads; z++)
                barrierLocal[currentId].Set();
            WaitHandle.WaitAll(barrier);
            /*
            for (int k = 0; k < numOfThreads; k++)
            {
                if (k == currentId)
                {
                    continue;
                }
                System.Console.Out.WriteLine("Thread {0} is about to wait for the singla from thread: {1}", name, k);
                barrierLocal[k].WaitOne();
                System.Console.Out.WriteLine("Thread {0} is about to wait for the singla from thread: {1}. done", name, k);
            }
            */
        }
    }
    static void Main(string[] args)
    {
        for (int i = 0; i < numOfThreads; i++)
        {
            barrier[i] = new AutoResetEvent(false);
        }
        for (int i = 0; i < numOfThreads; i++)
        {
            Thread t = new Thread(Program.barriers2);
            t.Name = Convert.ToString(i);
            t.Start(barrier);
        }
    }
}

我收到的输出如下:

线程0在'barrier'处将休眠7564在'barrier'处的线程1将为5123休眠在'barrier'处的线程2将为4237休眠线程2在时间4237的"屏障"处线程1位于时间为5123的"屏障"处线程0在'barrier'处,时间为7564在'barrier'处的线程0将休眠8641线程0在'barrier'处,时间为8641

就是这样。在最后一行之后,没有更多的输出,应用程序也不会终止。看起来好像出现了某种死锁。但是找不到问题。欢迎任何帮助。

谢谢!

如何在.net 3.5中实现.net 4中Barrier类的功能

这是因为你使用了AutoResetEvent。线程的一个WaitAll()调用将首先完成。这会自动在所有AREs上触发Reset()。这会阻止其他线程完成它们的WaitAll()调用。

下载。net 3.5的响应式扩展后端口。您将发现Barrier类以及。net 4.0中发布的其他有用的并发数据结构和同步机制。

这是我在XNA游戏中使用的实现。当我写这篇文章时,Barrier还没有可用,我仍然坚持使用。net 3.5。它需要三组manualreseteevents和一个计数器数组来保持相位。

using System;
using System.Threading;
namespace Colin.Threading
{
    /// <summary>
    /// Threading primitive for "barrier" sync, where N threads must stop at certain points 
    /// and wait for all their bretheren before continuing.
    /// </summary>
    public sealed class NThreadGate
    {
        public int mNumThreads;
        private ManualResetEvent[] mEventsA;
        private ManualResetEvent[] mEventsB;
        private ManualResetEvent[] mEventsC;
        private ManualResetEvent[] mEventsBootStrap;
        private Object mLockObject;
        private int[] mCounter;
        private int mCurrentThreadIndex = 0;
        public NThreadGate(int numThreads)
        {
            this.mNumThreads = numThreads;
            this.mEventsA = new ManualResetEvent[this.mNumThreads];
            this.mEventsB = new ManualResetEvent[this.mNumThreads];
            this.mEventsC = new ManualResetEvent[this.mNumThreads];
            this.mEventsBootStrap = new ManualResetEvent[this.mNumThreads];
            this.mCounter = new int[this.mNumThreads];
            this.mLockObject = new Object();
            for (int i = 0; i < this.mNumThreads; i++)
            {
                this.mEventsA[i] = new ManualResetEvent(false);
                this.mEventsB[i] = new ManualResetEvent(false);
                this.mEventsC[i] = new ManualResetEvent(false);
                this.mEventsBootStrap[i] = new ManualResetEvent(false);
                this.mCounter[i] = 0;
            }
        }
        /// <summary>
        /// Adds a new thread to the gate system.
        /// </summary>
        /// <returns>Returns a thread ID for this thread, to be used later when waiting.</returns>
        public int AddThread()
        {
            lock (this.mLockObject)
            {
                this.mEventsBootStrap[this.mCurrentThreadIndex].Set();
                this.mCurrentThreadIndex++;
                return this.mCurrentThreadIndex - 1;
            }
        }
        /// <summary>
        /// Stop here and wait for all the other threads in the NThreadGate. When all the threads have arrived at this call, they
        /// will unblock and continue.
        /// </summary>
        /// <param name="myThreadID">The thread ID of the caller</param>
        public void WaitForOtherThreads(int myThreadID)
        {
            // Make sure all the threads are ready.
            WaitHandle.WaitAll(this.mEventsBootStrap);
            // Rotate between three phases.
            int phase = this.mCounter[myThreadID];
            if (phase == 0)        // Flip
            {
                this.mEventsA[myThreadID].Set();
                WaitHandle.WaitAll(this.mEventsA);
                this.mEventsC[myThreadID].Reset();
            }
            else if (phase == 1)    // Flop
            {
                this.mEventsB[myThreadID].Set();
                WaitHandle.WaitAll(this.mEventsB);
                this.mEventsA[myThreadID].Reset();
            }
            else    // Floop
            {
                this.mEventsC[myThreadID].Set();
                WaitHandle.WaitAll(this.mEventsC);
                this.mEventsB[myThreadID].Reset();
                this.mCounter[myThreadID] = 0;
                return;
            }
            this.mCounter[myThreadID]++;
        }
    }
}

设置线程门:

private void SetupThreads()
{
    // Make an NThreadGate for N threads.
    this.mMyThreadGate = new NThreadGate(Environment.ProcessorCount);
    // Make some threads...
    // e.g. new Thread(new ThreadStart(this.DoWork);
}

线程工作者方法:

private void DoWork()
{
    int localThreadID = this.mMyThreadGate.AddThread();
    while (this.WeAreStillRunning)
    {
        // Signal this thread as waiting at the barrier
        this.mMyThreadGate.WaitForOtherThreads(localThreadID);
        // Synchronized work here...
        // Signal this thread as waiting at the barrier
        this.mMyThreadGate.WaitForOtherThreads(localThreadID);
        // Synchronized work here...
        // Signal this thread as waiting at the barrier
        this.mMyThreadGate.WaitForOtherThreads(localThreadID);
    }
}