我正在编写一个具有关键区域的应用程序。
我决定使用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()之前再次单击该按钮,整个应用程序就会停止响应。
在Debug窗口中,我发现了这样的东西
Entering Button_Click
Entering Button_Click看来这个方法永远不会完成。
我挣扎了一下,发现如果我把lock.WaitOne();改为
if (!sync.WaitOne(TimeSpan.FromSeconds(1)))
{
return;
}在这种情况下,我的应用程序能够避免死锁,但我不知道它为什么工作。
我只知道我的操作系统课程中的IPC,以及async和await在C#中的模式,而且我对.Net世界中的线程不太熟悉。
我真的很想了解幕后到底发生了什么。(谢谢你的答复;)
发布于 2016-08-16 09:35:03
您有死锁,因为WaitOne阻塞主线程(在主线程上执行按钮单击处理程序),而在调用await时没有调用ConfigureAwait(假),这意味着它试图在主线程上运行await之后的代码,即使它被阻塞,也会导致死锁。
我建议阅读这个职位,以更彻底地解释死锁的情况。
对于您的代码,我建议将锁放在更深的位置(可能在异步任务中),并尝试使用更合适的模式来锁定(最好是锁语句 ),因为使用Event对象对于互斥是很尴尬的,汉斯在评论中指出。
发布于 2016-08-16 09:27:42
AutoResetEvent.WaitOne()将无限阻塞,直到您调用AutoResetEvent.Set()为止,除了在WaitOne()调用之后,您似乎从未这样做过。
引用AutoResetEvent.WaitOne()文档:
阻塞当前线程,直到当前WaitHandle接收到信号为止。
https://stackoverflow.com/questions/38971043
复制相似问题