返回零倒数事件

问题描述:

我试图使用CountdownEvent只允许线程在事件的计数为零时继续,但是我希望初始计数为零。实际上,我想返回到零行为,从而当计数为零并且线程被设置为等待大于零时等待该事件。返回零倒数事件

我可以使用0初始计数来初始化倒计时事件,但是当我尝试添加计数时,我会得到InvalidOperationException“CountdownEvent_Increment_AlreadyZero”。

是否有其他类别或其他方式可以使用Countdown事件以避免此限制?

+0

你有没有解决过这个问题?你是怎么做到的? – HAL9000 2011-04-15 20:31:42

如何信号灯:http://msdn.microsoft.com/en-us/library/system.threading.semaphore.aspx

编辑:下面的帖子讨论为什么你描述是不推荐,什么也提出了一种解决方法:http://social.msdn.microsoft.com/Forums/en/parallelextensions/thread/aa49f92c-01a8-4901-9846-91bc1587f3ae

+0

你能举出一个如何使用它们的例子吗?我想到了他们,但无法避免需要知道最大数量。 – chillitom 2010-12-08 13:51:23

+0

你可以发布你的非工作代码,这样我可以更好地理解你想要实现的目标吗? – SpeksETC 2010-12-08 18:32:10

所以在本质上,你需要一个“ON/OFF开关”,不是可以用任意倒计数器设置的同步对象。 CountdownEvent不适合这种情况。

为什么不使用Semaphore,初始值为1?

+0

不完全,重要的是我有这种计数行为。实际上,我正在执行的操作将会创建未知数量的子操作(不是任务或线程),当每次操作开始时我会收到一个信号,并且每次操作结束时都会收到一个信号。我不想继续下去,直到所有的子操作完成。 (fyi,我在本地dll上写了一个相当棘手的约束,因此这是不寻常的要求) – chillitom 2010-12-08 13:56:15

如果您可以将.NET 4.0或Reactive Extensions用于.NET 3.5(它具有.NET 4 TPL功能的反向链接),那么可以查看Barrier类。它允许您协调多个并行任务,以使它们不会继续,直到障碍中的所有参与者发出信号表示其到达为止。它也应该满足您的要求,让参与者在处理过程中出现和消失。

您写道:

我执行,这将创建一个未知号码的孩子操作(没有任务或线程)

那么,什么是他们的工作?你应该做这样的事情:

 
CountdownEvent ev; 
public void foo() { 
    ev = new CountdownEvent(1); 
    foreach (<task in tasks_to_start>) { 
     ev.AddCount(); 
     // enter code here which starts your task 
    } 
    ev.Signal(); 
    ev.Wait(); 
} 

public static void youtTask(CountdownEvent ev) { 
    // some work 
    // ... 
    // after all is done 
    ev.Signal(); 
} 

您可以使用一个队列对象,以“工作”加入到并再次冒了出来。

只有当队列为空时,你才能继续前进。

但是,我们需要细节在这里...

这会为你工作吗? http://msdn.microsoft.com/en-us/library/dd384749.aspx

编辑
对不起,这是模糊的。使用SOReader的答案,如果每个家长都有一个倒计时事件,从1开始 - 然后在孩子中使用TryAddCount递增,然后将父母递减回1,然后在孩子完成时从父母递减到1,最后递减计数父线程的父代。因此,树状系列的倒数事件。

我没有多线程的经验,但乍一看这就是我会尝试。

你的问题似乎是一个常见的树行走分叉技术。每次你都要递归时,你会发起另一个并发操作(将它排入一个线程池等)。但是你需要等待所有子支路结束。只需为每次启动的子操作添加1到倒数事件,并在每个子操作结束时发出信号。只要您安排算法,只要它为每个子操作添加算法,它就不会发出信号,这是安全的。

我应该补充说,你不要需要知道计数前面,只需使它在根1,并且每次你分叉到一个孩子,加1,然后在每个一个,它会动态处理任何树,没有前期成本。

CountdownEvent有一个方法添加它可以让您增加飞行中的计数。

这有道理吗?我可能会远离你想要完成的事情。但是,如果您确实需要按照您指定的方式运行的CountdownEvent,则可以很容易地将一些互锁操作封装在类中以执行您所说的操作。

但是,CountdownEvent的构建是羽毛重量,如果没有人在信号发出之前等待,它几乎是免费的。在昂贵的情况下,它是最优的,无论有多少任务(等),它只会让一个内核转换到信号,一个等待,最坏的情况。

为了实现你的建议,需要围绕信号和事件重置进行同步。倒计时事件依赖于一个简单的原则,只有在信号调用中从非零到零的转换才可能发出事件信号。没有竞争,因为多个线程不可能同时更改值(它是互锁的),所以只有一个线程可以尝试发信号通知事件对象(唤醒另一个等待线程)。完善。但是,如果您有多个线程设置并将其重置,则需要同步设置和重置,因为计数可能会抖动几次,并且多个线程都会同时尝试设置或重置事件。 (设置,重置和等待事件都很昂贵,因为它们都必须进行内核转换并导致上下文切换)。除非您保护设置/重置转换,否则它将无法工作。如果他们将此添加到CountdownEvent中,它将不再是几乎最佳的,它将显着更昂贵。