Named Mutex with await
You must ensure that mutex is being accessed consistently on a certain thread. You could do that in a number of ways:
- Do not use await in the critical section during which you hold the mutex
- Invoke the mutex calls on a
TaskScheduler
that only has a single thread
That could look like this:
await Task.Factory.StartNew(() => mutex.WaitOne(), myCustomTaskScheduler);
Or, you use synchronous code and move everything to the thread-pool. If you only have access to an async version of DoSomething
, consider just calling Task.Wait
on its result. You'll suffer a minor inefficiency here. Probably fine.
Calling await operation after acquiring mutex
This is a job for a monitor (or to make this more async-friendly, a semaphore), not a mutex.
The problem is that the continuation to WriteTextAsync
is likely to run on a separate thread, so it can't release the mutex - that can only be done from the same thread that originally acquired the mutex.
var semaphore = new SemaphoreSlim(1);
await semaphore.WaitAsync();
try
{
await FileIO.WriteTextAsync(filename, text);
Debug.WriteLine("written");
}
finally
{
semaphore.Release();
}
How to use named mutexes and async/await in .NET Core 3.1?
The linked solution only works when using a named mutex to synchronize asynchronous code across processes. It won't work to synchronize code within the same process. Mutexes allow recursive acquisition, so by moving all acquisitions on the same thread, it's the same as if the mutex isn't there at all.
I'd have to keep all my semaphores in a Dictionary<string, SemaphoreSlim> and that would be too cumbersome to manage.
If you need a non-recursive named mutex, named Semaphore
s (which don't work on Linux) or managing your own dictionary is really the only way to go.
I have an AsyncCache<T>
that I've been working on but isn't prod-ready yet. It tries to look like a cache of Task<T>
instances but is actually a cache of TaskCompletionSource<T>
instances.
Wrapping a Mutex with IDisposable and testing it but the test never ends
This happens because of await
. After your await Task.Delay(..)
you might no longer be on the same thread you were before await
statement. So in some cases you are trying to release your mutex from the thread which does not own it - hence your problem. That's easy to verify by writing current thread before and after await:
class Program {
public static void Main() {
while (true) {
var sw = Stopwatch.StartNew();
var task1 = Task.Run(async () => {
using (new NamedMutex("foo")) {
Console.WriteLine("first before await: " + Thread.CurrentThread.ManagedThreadId);
await Task.Delay(TimeSpan.FromSeconds(2));
Console.WriteLine("first after await: " + Thread.CurrentThread.ManagedThreadId);
}
});
var task2 = Task.Run(async () => {
using (new NamedMutex("foo")) {
Console.WriteLine("second before await: " + Thread.CurrentThread.ManagedThreadId);
await Task.Delay(TimeSpan.FromSeconds(1));
Console.WriteLine("second after await: " + Thread.CurrentThread.ManagedThreadId);
}
});
Task.WaitAll(task1, task2);
//Assert.IsTrue(sw.Elapsed.TotalSeconds >= 5);
Console.WriteLine(sw.Elapsed);
}
}
}
Related Topics
Relative Path to Absolute Path in C#
Launching Process in C# Without Distracting Console Window
Get Ipv4 Addresses from Dns.Gethostentry()
How to Define Multiple Names for Xmlelement Field
How to Put Text on Progressbar
How Should You Diagnose the Error Sehexception - External Component Has Thrown an Exception
Add Vertical Scroll Bar to Panel
Get Just the Domain Name from a Url
Get String Name of Property Using Reflection
How to Write a Transaction to Cover Moving a File and Inserting Record in Database
Save Modified Wordprocessingdocument to New File
Patch Async Requests with Windows.Web.Http.Httpclient Class
How to Calculate the Average Rgb Color Values of a Bitmap
Edit Raw Pixel Data of Writeablebitmap