C# 如何在.NET3.5中实现.NET4功能中的Barrier类
出于某些原因,我必须坚持使用.NET3.5,并且我需要.NET4中的Barrier类功能。我有一堆线程做一些工作,我希望它们互相等待,直到所有的工作都完成。当所有的工作都完成后,我希望他们以同样的方式一次又一次地做这项工作。 在线程的鼓励下,我决定用AutoResteEvent和WaitHandle类实现Barrier功能。 尽管我的代码遇到了问题:C# 如何在.NET3.5中实现.NET4功能中的Barrier类,c#,multithreading,barrier,cyclicbarrier,C#,Multithreading,Barrier,Cyclicbarrier,出于某些原因,我必须坚持使用.NET3.5,并且我需要.NET4中的Barrier类功能。我有一堆线程做一些工作,我希望它们互相等待,直到所有的工作都完成。当所有的工作都完成后,我希望他们以同样的方式一次又一次地做这项工作。 在线程的鼓励下,我决定用AutoResteEvent和WaitHandle类实现Barrier功能。 尽管我的代码遇到了问题: class Program { const int numOfThreads = 3; static AutoResetEven
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);
}
}
}
类程序
{
常量int numOfThreads=3;
static AutoResetEvent[]barrier=新的AutoResetEvent[numOfThreads];
静态随机=新随机(System.DateTime.Now.毫秒);
静态空隙屏障2(对象屏障BJ)
{
自动还原事件[]barrierLocal=(自动还原事件[])barrierObj;
字符串名称=Thread.CurrentThread.name;
对于(int i=0;i<10;i++)
{
int sleepTime=random.Next(200010000);
System.Console.Out.WriteLine(“barrier”处的线程{0}将睡眠{1}。”,名称,睡眠时间);
睡眠(睡眠时间);
System.Console.Out.WriteLine(“线程{0}位于时间为{1}的“屏障”处”,名称,休眠时间);
int currentId=Convert.ToInt32(名称);
//对于(intz=0;z
我收到的输出如下:
“屏障”处的线程0将休眠7564秒
“屏障”处的线程1将休眠5123
“屏障”处的线程2将休眠4237秒
时间为4237的“屏障”处的螺纹2
时间为5123的“屏障”处的螺纹1
线程0位于“屏障”处,时间为7564
“屏障”处的线程0将休眠8641
时间为8641的“屏障”处的线程0
就这样。在最后一行之后,没有更多的输出,应用程序也不会终止。看起来好像出现了某种僵局。但是找不到问题。欢迎任何帮助
谢谢 那是因为您使用AutoResteEvent。线程的一个WaitAll()调用将首先完成。这会自动在所有战神上重置()。这会阻止其他线程完成其WaitAll()调用
此处需要手动重置事件。下载.NET 3.5的后端口。您将发现
Barrier
类以及.NET 4.0中发布的其他有用的并发数据结构和同步机制。以下是我的应用程序实现。当我写这篇文章时,屏障是不可用的,我仍然坚持使用.NET3.5。它需要三组手动复位事件和一个计数器阵列来保持相位
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 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);
}
}
汉斯,谢谢你的回答。这可以解释问题,但在ManualResetEvent类中,必须有一些线程在所有线程通过“屏障”后重置MRE。你知道在我的场景中该怎么做吗?从阅读Barrier源代码中获得一些灵感,比如说,Reflector。我认为它使用两组MRE(命名为奇数和偶数)并在它们之间交替。您认为这样一个简单的解决方案怎么样:
lock(obj){threadscont++;if(threadscont==numOfThreads){System.Console.WriteLine(“所有线程都已完成。”);threadScont=0;Monitor.pulsell(obj);}else{Monitor.Wait(obj);}您好,谢谢您的回答。是否可以从这个后端口获取Barrier类,或者我必须始终引用整个包?谢谢。问题是,它是为了一个大型项目的目的,不能强迫其他很多人在生产环境中安装extenstion+。您不必安装RX framework on目标计算机。事实上,如果不想,您不必在开发计算机上安装它。只需获取它附带的System.Threading.dll库,并像其他任何第三方库一样引用它。我就是这么做的。
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);
}
}