C# 如何安全地处置WaitHandle?

C# 如何安全地处置WaitHandle?,c#,multithreading,winapi,event-wait-handle,C#,Multithreading,Winapi,Event Wait Handle,考虑以下代码: volatile EventWaitHandle waitHandle; // Thread1, represents an IO-bound worker thread: while (true) { waitHandle?.Set(); } // Thread 2, represents some "main" thread: waitHandle = new AutoResetEvent(true); waitHandle.WaitOne();

考虑以下代码:

volatile EventWaitHandle waitHandle;

// Thread1, represents an IO-bound worker thread:
while (true) {
  waitHandle?.Set();
}

// Thread 2, represents some "main" thread:
waitHandle = new AutoResetEvent(true);
waitHandle.WaitOne();
Sleep(1000);  // To simulate some work.
// Close the wait handle; we're done with it.
EventWaitHandle handle = waitHandle;
waitHandle = null;
handle?.Close();
null合并运算符意味着从thread1访问waitHandle是安全的。设置引用类型的原子性(加上它被标记为volatile)意味着在设置waitHandle之后访问waitHandle对于线程2是安全的。AutoResetEvent(以及所有从EventWaitHandle继承的类)是线程安全的。很天真,这一切都应该是线程安全的

但是,如果线程1在线程2关闭句柄时位于Set()方法内,这会导致未定义的行为/争用条件吗?查看.NET引用实现中的代码,我看不到任何明显的机制可以防止这种情况

Close调用Dispose,它位于SafeWaitHandle上,最终位于WinAPI中。在WinAPI中设置调用。在这两种情况下,我都看不到任何其他明显的线程机制,因此似乎有可能出现这样的情况:一个线程在同一个句柄上调用CloseHandle,另一个线程在同一个句柄上调用SetEvent。如果先调用SetEvent,则没有问题,但如果先调用CloseHandle,则可能会导致问题

我试着到处阅读文档,但我仍然不清楚

这是否是潜在的竞争条件/未定义的行为?如果是问题,正确的处理方法是什么?我总是可以在锁中封装Set和Close调用,但在另一种同步机制中封装对互斥的访问似乎很奇怪


作为参考,我找到了这个。那里的指导是不要关闭手柄,但博客链接是一个死链接,在我嘴里留下不好的味道后,可识别的东西没有清理就挂了起来。这仍然是处理此问题的正确方法吗?

您有什么理由不能使用.net本机同步工具吗?在大多数不需要互操作的情况下,它们会工作得更好。我会退一步,问一下,为什么在其他线程可能仍在使用的东西上调用
Close
。有一件事需要假定这个对象的所有权,而且有些事必须对其他生命周期有足够的了解,以便知道什么时候没有其他东西在使用句柄,然后关闭它。@Mgetz我正在使用.net同步工具。只是这些工具将WinAPI调用包装在了幕后。@Damien_不相信者从概念上说,可能需要做一些工作。这些工作的生命周期比两个线程中的任何一个都短(并且一次只有一个工作处于活动状态)。目前,我正在使用WaitHandle访问该工作,我的想法是在工作项死亡并被替换时替换WaitHandle。如果这是一个好主意或不是一个好主意,可能值得进行一次完整的讨论,但这可能超出了此问题的范围。关闭无效句柄会引发在调试时捕获的第一次异常-0xC0000008:指定了无效句柄。您通常等待这些事件(或线程句柄)。你不会期望一切顺利就关闭它们。除了WaitXXX方法外,不能使用任意超时(睡眠)。