AutoResetEvent.WaitOne()导致死锁
本文关键字:死锁 WaitOne AutoResetEvent | 更新日期: 2023-09-27 18:02:30
我正在编写一个具有临界区域的应用程序。
我决定使用AutoResetEvent来实现互斥。下面是代码
public class MyViewModel
{
private AutoResetEvent lock = new AutoResetEvent(true);
private aync Task CriticalRegion()
{
Dosomething();
}
public async Task Button_Click()
{
Debug.WriteLine("Entering Button_Click");
lock.WaitOne();
try
{
await CriticalRegion();
}
finally
{
lock.Set();
Debug.WriteLine("Leaving Button_Click");
}
}
}
我有一个按钮,它的点击事件调用Button_Click()
方法
工作正常。但是,如果我足够快地在第一次调用Button_Click()
完成之前再次点击按钮,整个应用程序停止响应。
在调试窗口,我发现这样的东西
Entering Button_Click
Entering Button_Click
看起来这个方法永远不会完成。
我挣扎了一下,发现如果我把lock.WaitOne();
改为
if (!sync.WaitOne(TimeSpan.FromSeconds(1)))
{
return;
}
在这种情况下,我的应用程序能够避免死锁,但我不知道为什么它工作。
我只从我的OS课程和c#中的async
和await
模式中了解IPC,我对。net世界中的线程不太熟悉。
你有一个死锁,因为WaitOne
阻塞主线程(按钮点击处理程序在主线程上执行),而你还没有调用ConfigureAwait(false)时,调用await
,这意味着它试图运行代码之后的await
在主线程上,即使它被阻塞,这将导致死锁。
我建议阅读这篇文章,以获得关于死锁情况的详细解释。
对于您的代码,我建议将锁放在更深的地方,可能在async Task中,并尝试使用更合适的锁模式,最好是锁语句,因为使用Event
对象对于互斥是尴尬的,正如Hans在评论中所说的。
AutoResetEvent.WaitOne()
将无限阻塞,直到您调用 AutoResetEvent.Set()
,您似乎永远不会这样做,除了在 WaitOne()
调用之后。
引用AutoResetEvent.WaitOne()
文档:
阻塞当前线程,直到当前waithhandle接收到信号。