我正在使用一个使用ManualResetEvent同步线程的应用程序。 FxCop告诉我处理这些物品。我发现以下讨论告诉了我同样的事情:
Do I need to Dispose() or Close() an EventWaitHandle?
但我不知道何时处理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();
}
问题是存在多个ManualResetEvent实例,并且多个线程正在等待每个实例。
如果我记住列表中的实例,我不知道何时处理它。在WaitOne()之后处理它 - 调用将多次处理它,并且可能在其他线程仍在等待时处理它。
创建事件的线程没有任何对它的引用。 setter-thread不应该处置它,因为还有其他线程在等待这个MRE。每个等待的线程都不能像前面提到的那样处理它。
所以问题是:什么时候应该处理这个ManualResetEvent?
答案 0 :(得分:5)
ManualResetEvent
应在您不再需要时处理。你真正的问题是,“我怎么知道我不再需要它?”
通常在线程完成时会通知某些内容,并在线程上调用Join。或者线程设置一些事件以指示它已完成。如果你有多个线程,他们都可以发出CountdownEvent信号。还有其他几种管理线程通知的方法。
重点是,如果您要分配资源,则由您决定是否正确配置。在上面的代码中,您无法跟踪哪些线程正在执行或哪些线程与哪个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
}
是的,这是很多工作。如果您可以构建程序以便不必执行此类操作,则可能是最好的。