如何在.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
就是这样。在最后一行之后,没有更多的输出,应用程序也不会终止。看起来好像出现了某种死锁。但是找不到问题。欢迎任何帮助。
谢谢!
这是因为你使用了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);
}
}