【问题标题】:Global Mutex with Async Await [duplicate]具有异步等待的全局互斥锁[重复]
【发布时间】:2019-02-05 03:52:58
【问题描述】:

我有一段代码应该一次只能由一个进程运行。为了确保机器上只有一个进程在运行这个关键块,我使用了全局互斥锁。关键部分的代码使用 async/await。总体而言,代码如下所示:

var mutex = new Mutex(false, @"Global\MyMutexName");    
mutex.WaitOne(-1, false);   
SetupASystemWideResource() 
await DoSomeAsyncWorkOnThatResource();    
mutex.ReleaseMutex();

问题是等待之后的代码可能发生在不同的线程上。因此,互斥锁可能会在与获取的线程不同的线程上释放。这会导致异常

System.ApplicationException: Object synchronization method was called from an unsynchronized block of code.

通常这是因为您不希望使用不同的线程来释放互斥锁而不是获取它。但是在我的情况下,我真的只对防止应用程序的第二个实例在第一个实例使用它时以不同的方式设置系统资源感兴趣。资源本身可以在一个实例中的多个线程中使用。

确保这一点并异步完成工作的正确方法是什么?

【问题讨论】:

  • 你能在 UI 线程上做到这一点吗(假设 WinFroms/WPF)?

标签: c# async-await mutex


【解决方案1】:

如果我理解问题,并且这是一个控制台应用程序或没有同步上下文,只需调用Wait,不用担心死锁,它应该可以正常工作

var mutex = new Mutex(false, @"Global\MyMutexName");    
mutex.WaitOne(-1, false);

DoSomeAsyncWorkOnThatResource().Wait();
mutex.ReleaseMutex();

或者如果你真的必须(并且更有争议)你可以使用

Task.Run(async () => await DoSomeAsyncWorkOnThatResource()).Wait();

您可以做的另一件事是使用自定义调度程序,例如 CurrentThreadTaskScheduler(我第一次看到您使用它),如 Stephen Toubs Parallel Programming with .NET 中所述。 NugetParallelExtensionsExtras

在请求调度时在当前线程上运行所有任务

并将它与Task.Factory.StartNew 或需要调度程序的东西一起使用

【讨论】:

    【解决方案2】:

    信号量不要求由同一个线程释放。因此,即使 async 方法在不同的线程上继续,以下内容也有效。这里最大的缺点是如果应用程序在工作期间崩溃或被杀死,则不会释放信号量,因此应用程序的下一次运行将挂起。见Abandoned named semaphore not released

    var semaphore = new Semaphore(1, 1, @"Global\MySemaphoreName");    
    semaphore.WaitOne(-1, false);   
    SetupASystemWideResource() 
    await DoSomeAsyncWorkOnThatResource();    
    semaphore.Release();
    

    【讨论】:

      猜你喜欢
      • 2012-06-05
      • 2010-12-07
      • 2015-07-12
      • 1970-01-01
      • 1970-01-01
      • 2014-09-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多