名为Mutex等待

因此我不能使用async线程仿射锁 – 如何在运行多个进程时保护我的资源?

例如,我有两个使用以下任务的进程:

  public async Task MutexWithAsync() { using (Mutex myMutex = new Mutex(false, "My mutex Name")) { try { myMutex.WaitOne(); await DoSomething(); return true; } catch { return false; } finally { myMutex.ReleaseMutex(); } } } 

如果由Mutex保护的moethod是同步的,那么上面的代码将起作用但是async我会得到:

从不同步的代码块调用对象同步方法。

那么命名Mutex对异步代码没用吗?

您必须确保在某个线程上一致地访问互斥锁。 你可以通过多种方式做到这一点:

  1. 不要在持有互斥锁的关键部分中使用等待
  2. 在仅具有单个线程的TaskScheduler上调用互斥锁调用

这看起来像这样:

 await Task.Factory.StartNew(() => mutex.WaitOne(), myCustomTaskScheduler); 

或者,您使用同步代码并将所有内容移动到线程池。 如果您只能访问DoSomething的异步版本,请考虑在其结果上调用Task.Wait 。 你在这里会遭受轻微的低效率。 可能还不错。

我有一个有趣的解决方案给你。 没有时间提供代码示例,所以如果我的描述不够,请告诉我,我会尝试提供代码。

你这里有两个问题。 首先,AsyncMutex没有线程关联,正如您所指出的那样。 所以你不能用Mutex构建一个。 但是,你可以用一个计数为1的信号量构建一个,因为信号量也没有线程关联。 在C#中,可以跨进程边界命名和使用Semaphore类。 所以第一个问题很容易解决。

第二个问题是当你“锁定”这个AsyncMutex时不想使用阻塞调用。 好吧,你可以使用ThreadPool.RegisterWaitForSingleObject来注册一个回调函数,以便在信号量(WaitHandle)发出信号时执行。 这会进行“异步等待”。 使用TaskCompletionSource包含一些代码,您可以非常轻松地在AsyncMutex上构建一个返回WaitAsync方法的Task。 这两个想法应该可以很容易地实现在C#中可用的名为AsyncMutex的跨进程。

请记住,就像你会发现的其他AsyncMutex实现一样,这不是递归互斥锁(相同的“线程”可以多次锁定互斥锁,只要它以相同的次数解锁互斥锁),所以必须小心在代码中采取不会导致死锁。

这个防护与async / await完美配合:

 public sealed class AsyncLock : IDisposable { readonly AutoResetEvent Value; public AsyncLock(AutoResetEvent value, int milliseconds = Timeout.Infinite) { if (value == null) throw new ArgumentNullException("value"); value.WaitOne(milliseconds); Value = value; } void IDisposable.Dispose() { Value.Set(); } } private async Task TestProc() { var guard = new AutoResetEvent(true); // Guard for resource using (new AsyncLock(guard)) // Lock resource { await ProcessNewClientOrders(); // Use resource } // Unlock resource }