Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/264.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# 应在何时处理ManualReset事件?_C#_.net_Multithreading_Idisposable_Manualresetevent - Fatal编程技术网

C# 应在何时处理ManualReset事件?

C# 应在何时处理ManualReset事件?,c#,.net,multithreading,idisposable,manualresetevent,C#,.net,Multithreading,Idisposable,Manualresetevent,我使用的应用程序使用ManualResetEvent同步线程。FxCop让我处理那些东西。我发现下面的讨论告诉了我同样的情况: 但我不知道何时处理ManualResetEvent的实例 以下简化代码演示了该问题: private void btn_Click(object sender, EventArgs e) { var mre = new ManualResetEvent(false); new Thread(() => this.SetEvent(mre)).St

我使用的应用程序使用ManualResetEvent同步线程。FxCop让我处理那些东西。我发现下面的讨论告诉了我同样的情况:

但我不知道何时处理ManualResetEvent的实例

以下简化代码演示了该问题:

private void btn_Click(object sender, EventArgs e)
{
    var mre = new ManualResetEvent(false);
    new Thread(() => this.SetEvent(mre)).Start();
    for (int i = 0; i < 10; ++i)
    {
        new Thread(() => this.WaitFor(mre)).Start();
    }
}

private void SetEvent(ManualResetEvent manualResetEvent)
{
    Thread.Sleep(10000);
    manualResetEvent.Set();
}

private void WaitFor(ManualResetEvent manualResetEvent)
{
    manualResetEvent.WaitOne();
}
private void btn\u单击(对象发送者,事件参数e)
{
var mre=新手动重置事件(错误);
新线程(()=>this.SetEvent(mre)).Start();
对于(int i=0;i<10;++i)
{
新线程(()=>this.WaitFor(mre)).Start();
}
}
私有无效设置事件(手动重置事件手动重置事件)
{
睡眠(10000);
manualResetEvent.Set();
}
私有无效等待(手动重置事件手动重置事件)
{
manualResetEvent.WaitOne();
}
问题是存在ManualResetEvent的多个实例,并且多个线程正在等待每个实例

如果我记住了列表中的实例,我不知道什么时候处理它。WaitOne()之后处理它-调用将多次处理它,并且可能会在其他线程仍在等待时处理它

创建事件的线程没有对它的任何引用。setter线程不应处理它,因为还有其他线程等待此MRE。每个等待的线程都无法像前面提到的那样处理它


因此,问题是:何时应处置此ManualResetEvent?

当您不再需要时,应处置
ManualResetEvent
。你真正的问题是,“我怎么知道我不再需要它?”

通常情况下,当线程完成时会通知某些内容,并且您会调用该线程。或者线程设置一些事件以指示它已完成。如果有多个线程,它们都可以发出一个信号。还有其他几种方法可以管理线程通知

关键是,如果你在分配资源,就要由你来确保它们被正确地处置。在上面的代码中,您无法跟踪哪些线程正在执行,或者哪些线程与哪个
ManualResetEvent
关联。如果您想确保正确处置MRE,那么您必须跟踪它,不仅要跟踪MRE,还要跟踪哪些线程正在使用它,哪些线程已经完成了它们的工作,并在所有线程都完成时收到通知,以便您可以处置事情

在您的特定情况下,如果您真的必须以这种方式使用MRE,我可能会创建一个包含对线程和MRE的引用的数据结构,以及一个
CountdownEvent
,线程在完成时会发出信号。比如:

class WorkUnit
{
    public List<Thread> Threads;
    public ManualResetEvent MRE;
    public CountdownEvent CE;
}
程序的其他部分(可能是主线程)定期检查工作单元列表。对于该列表中的每个项目,它都会执行以下操作:

workUnit.CE.Signal();
if (workUnit.CE.WaitOne(0))
{
    foreach (Thread t in workUnit.Threads)
    {
        t.Join();
    }
    // dispose the MRE and the CE
    // and remove the work unit from the list
}

是的,工作量很大。如果你能构造你的程序,这样你就不必做这种事情,那可能是最好的。

代码是毫无意义的,而且只有一个MRE实例。在方法末尾处理它是可以的。不,我不这么认为。创建MRE的代码是一个按钮单击事件处理程序。您可以多次单击它以创建多个MRE。上面的代码被简化了。在该方法结束时处理MRE将不起作用,因为在该方法完成后有11个线程正在使用该MRE。setter线程等待10秒,其他10个线程正在等待此MRE。谢谢Jim。唯一的问题是,我不知道有多少线程将等待MRE,这就是为什么我不能初始化倒计时事件。但你是对的,我应该考虑一个设计,知道什么时候不再需要MRE。目前没有线程等待工作线程的结束,因为它们计算一些值并在控件中显示结果。之后,任务(哦,是的,我使用任务而不是线程,但我认为问题仍然是一样的,因为任务可以使用ContinueWith设置CountDownEvent)结束,并且没有代码显式地等待它。我为我的案例找到了解决方案。setter线程仅在一个返回MRE的方法中创建和启动。此方法的调用方知道MRE并将其传播到多个线程,但它知道接收方。我能够将MRE包装到一个处理程序对象中,该对象管理MRE接收器并等待结束。之后,可以释放MRE。谢谢你的帮助。