C#中的互斥锁 - 来自非同步代码块的同步

Sam*_*ski 2 c# multithreading async-await

我正在编写一个程序,从网站下载游戏作为zip存档并提取它们.由于所有游戏在被提取之前都被下载到同一位置,因此我在使用Mutex时可以防止同时进行两次下载时的竞争条件.问题是我得到一个System.ApplicationException抛出说:"对象同步方法是从一个不同步的代码块调用的." 我所看到的一切都说这是因为从不拥有它的线程中释放Mutex.但是,我的代码等待并在同一个线程中释放互斥锁.

await Task.Run(async () =>
{
   mutex.WaitOne();
   await DownloadGameAsync(ug, nvm);
   await ExtractGameAsync(ug, nvm);
   nvm.Action = "Done";
   mutex.ReleaseMutex();
});
Run Code Online (Sandbox Code Playgroud)

如果我在线上放置一个断点mutex.ReleaseMutex(); 并且跳过该行不会导致抛出异常,但是删除断点并正常运行会导致每次执行都出现异常.

我应该以不同的方式接近(信号量)还是使用async/await导致问题?

Ste*_*ary 7

在一般情况下,不能使用线程仿射同步原语(例如,a Mutex)async.具体来说,之后你的代码await保证相同的线程中获取互斥的线程上运行.

我建议使用SemaphoreSlim它的WaitAsync方法.SemaphoreSlim是唯一保证与之正常工作的BCL同步原语await.如果你需要更复杂的同步原语,Stephen Toub写了一系列关于这个主题的博客文章,我将其扩展并包含在我的AsyncEx库中.