考虑这段代码:
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 对线程 2 是安全的。 AutoResetEvent(实际上所有继承自 EventWaitHandle 的类)都说它是线程安全的。所以天真这应该都是线程安全的。
但是,如果线程 1 在 Thread2 关闭句柄时位于 Set() 方法内,这会导致未定义的行为/竞争条件吗?查看 .NET 参考实现中的代码,我看不到任何明显的机制可以防止这种情况发生。
Close 调用 Dispose,后者在 SafeWaitHandle 上调用 Close ,后者最终在 WinAPI 中调用 CloseHandle 。Set在 WinAPI 中调用SetEvent 。在这两种情况下,我都没有看到任何其他明显的线程机制,因此我可能最终会遇到一个线程在同一个句柄上调用 CloseHandle 另一个线程正在调用 SetEvent 的情况。如果先调用 SetEvent 没有问题,但如果先调用 CloseHandle 可能会导致问题?
我已经尝试阅读有关CloseHandle和SetEvent的文档,但我仍然不清楚。
这是潜在的竞争条件/未定义的行为吗?如果是问题,正确的处理方法是什么?我总是可以将对 Set 和 Close 的调用包装在一个锁中,但是在另一个同步机制中包装对互斥锁的访问似乎很奇怪。
作为参考,我发现这个较旧的问题基本上是相同的问题。那里的指导是毕竟不要关闭手柄,但是链接的博客是一个死链接,并且 IDisposable 对象挂起而没有清理,因为它们在我的嘴里留下了不好的味道。这仍然是处理这个问题的正确方法吗?