Mutex ApplicationException when using async/await

Bla*_*_99 0 c# mutex asynchronous httpclient async-await

I am trying to get the response from a url, and when I use the await and async in my function, my Mutex throws an error.

Error output :

System.ApplicationException
Object synchronization method was called from an unsynchronized block of code.
 at System.Threading.Mutex.ReleaseMutex()
Run Code Online (Sandbox Code Playgroud)

Code :

private async void getData ()
{
    _mutex.WaitOne();

    try
    {
        string url = "https://urllink.com";
        HttpClient client = new HttpClient();
        string response = await client.GetStringAsync(url);
    }
    catch (Exception e)
    {
        // TODO
        throw e;
    }
           
    _mutex.ReleaseMutex();
}
Run Code Online (Sandbox Code Playgroud)

Mar*_*ell 5

I would propose two three changes here:

  1. replace async void with async Task (credit: Fildor), and make sure you await it
  2. replace Mutex with SemaphoreSlim (a new SemaphoreSlim(1,1) is basically the same thing as a Mutex) - the Mutex documentation is heavily focused on "the thread that owns the mutex", which strongly suggests it is thread-bound, and await is incompatible with thread-bound scenarios; SemaphoreSlim, however, is not thread-bound; additionally, it has an async-aware WaitAsync() API, avoiding thread blocks (i.e. replace _mutex.WaitOne(); with await _semaphore.WaitAsync();)
  3. put the release in a finally, so that it is released even in the failure case

But "1" seems to be the real problem here. I would also speculate that this code worked fine until it was changed to async.

您也可以删除catch, 因为catch刚刚拥有的 athrow是多余的;一catch,仅仅有throw e;雪上加霜不是多余的:它打破了堆栈跟踪。

  • 您 **不能** 在代码中使用 Mutex,因为 `await` 可能会转换到不同的线程。你**会**有这个问题。您可以将大部分代码保持原样,但您需要更改为没有线程关联的同步对象。[AsyncEx by Stephen Cleary](https://github.com/StephenCleary/AsyncEx) 如果您希望锁获取也是异步的,可以使用很多替代方法。如果这不是问题,您可以按照 Marc 的描述切换到 SemaphoreSlim。 (2认同)
  • 我还强烈建议不要使用“async void”,而使用“async Task”。并重用 HttpClient 实例,而不是在每次调用时创建一个新实例。 (2认同)