Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/278.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/25.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 返回零倒计时事件_C#_.net_Multithreading_Countdownevent - Fatal编程技术网

C# 返回零倒计时事件

C# 返回零倒计时事件,c#,.net,multithreading,countdownevent,C#,.net,Multithreading,Countdownevent,我试图使用仅在事件计数为零时允许线程继续,但是我希望初始计数为零。实际上,我想要一种返回到零的行为,即每当计数为零时,事件就会发出信号,每当计数大于零时,线程就会等待 我可以初始化一个初始计数为0的倒计时事件,但当我尝试添加到计数时,我会得到InvalidOperationException“CountdownEvent\u Increment\u AlreadyZero” 是否有其他类或其他方式可以使用倒计时事件来避免此限制?信号量如何: 编辑:下面的帖子讨论了为什么不推荐您所描述的内容,并提

我试图使用仅在事件计数为零时允许线程继续,但是我希望初始计数为零。实际上,我想要一种返回到零的行为,即每当计数为零时,事件就会发出信号,每当计数大于零时,线程就会等待

我可以初始化一个初始计数为0的倒计时事件,但当我尝试添加到计数时,我会得到InvalidOperationException“CountdownEvent\u Increment\u AlreadyZero”

是否有其他类或其他方式可以使用倒计时事件来避免此限制?

信号量如何:

编辑:下面的帖子讨论了为什么不推荐您所描述的内容,并提出了解决方法:

因此本质上您需要一个“开/关开关”,而不是一个可以设置为任意倒计时的同步对象<代码>倒计时事件不适用于此类情况


为什么不使用初始计数为1的?如果可以使用.NET 4.0或.NET 3.5(具有.NET 4 TPL功能的后端口),则可以签出该类。它允许您协调多个并行任务,以便在屏障中的所有参与者发出到达信号之前,这些任务不会继续。它还应该满足您的要求,让参与者在处理过程中出现和消失。

Edit
您可以使用队列对象将“工作”添加到队列中并再次取出

只有当队列为空时,才能继续

但是是的,我们需要这里的细节…

这对你有用吗

编辑
对不起,这是含糊不清的。使用SOReader的答案,其中每个父线程中都有一个从1开始的倒计时事件-然后在子线程中使用TryAddCount递增,然后将父线程中的父线程减量回1,然后在子线程完成时,在父线程中从1减量到零,最后在父线程中减量。一系列类似树的倒计时事件


我对多线程没有经验,但乍一看我会试试。

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

我应该补充一点,你不需要知道前面的计数,只需要在根处设为1,每次你给一个孩子分岔时,加上1,然后在每个树的末尾发出信号,它将动态地处理任何树,而不需要预先付费

CountdownEvent有一个Add方法,可用于增加飞行中的计数

这有意义吗?我可能远远偏离了你想要实现的目标

但是,如果您真的希望CountdownEvent按照您指定的方式运行,那么在一个类中封装两个互锁的操作来执行您所说的操作是非常容易的

然而,倒计时事件是轻量级的,如果在发出信号之前没有人等待,它几乎是免费的。在代价昂贵的情况下,它是最优的,不管有多少任务(等),它只需要一个内核转换为信号,一个内核转换为等待,这是最坏的情况

要实现您的建议,需要围绕事件的信令和重置进行同步。倒计时事件依赖于一个简单的原理,只有信号调用中从非零到零的转换才可能向事件发送信号。不存在争用,因为一次不可能有多个线程更改该值(它是互锁的),所以只有一个线程可以尝试向事件对象发送信号(唤醒另一个等待的线程)。太好了

但是,如果您有多个线程设置并重置它,则需要围绕设置同步并重置,因为计数可能会抖动几次,并且多个线程将同时尝试设置或重置事件。(设置、重置和等待事件都很昂贵,因为它们都必须进行内核转换并导致上下文切换)。除非您围绕某些东西进行同步以保护设置/重置转换,否则它将无法工作。如果他们将此添加到倒计时事件中,它将不再是接近最优的,它将显著更昂贵。

我遇到了相同的情况,但在
障碍的上下文中

实际上,如果你仔细想想,
CountdownEvent
是一个单阶段的
屏障

因此,为了避免以下限制:

我可以初始化一个初始计数为0的倒计时事件,但是当我尝试 要添加到计数中,我会得到InvalidOperationException “倒计时事件增量”


您可以继续使用
Barrier
并使用其
addparticipan
RemoveParticipan
方法。

您能举例说明如何使用它们吗?我考虑过它们,但无法摆脱需要知道最大计数的需要。你能发布你的非工作代码,以便我更好地理解你试图达到的目的吗?不完全是,我有这种计数行为很重要。实际上,我正在执行一个操作,该操作将创建未知数量的子操作(不是任务或线程),当每个操作开始时,我收到一个信号,当每个操作结束时,我收到一个信号。在所有子操作完成之前,我不想继续。(仅供参考,我正在围绕本机dll编写一个相当棘手的绑定,因此有一个不寻常的要求)这些(数量未知)操作是一次性创建的,还是有可能“批量”创建?换句话说,你能说“好的,我创造了X个,a
public void Dispatch()
{
    using (var ev = new CountdownEvent(1))
    {
        foreach (var task in <collection_of_tasks_to_start>)
        {
            ev.AddCount();
            // start *task* here. Don't forget to pass *ev* to it!
        }

        ev.Signal();
        ev.Wait();
    }
}

// task code
void Handler(CountdownEvent ev)
{
    try
    {
        // do task logic
    }
    finally
    {
        ev.Signal();
    }
}
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(); }