HiveBrain v1.2.0
Get Started
← Back to all entries
patterncsharpModerate

Implementing an asynchronous mutex in C#

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
asynchronousimplementingmutex

Problem

I wrote a simple synchronization primitive that I can use with async operations on an external REST service so that I don't call it twice from different threads and have one call fail due to not having the latest state. Despite obvious limitations of that design decision I think this should solve my problem...

struct DumbAsyncMutex
{
    int busy;

    public async Task WithMutexAsync(Func t)
    {
        while (Interlocked.CompareExchange(ref busy, 1, 0) != 0)
        {
            await Task.Delay(100);
        }

        try
        {
            await t();
        }
        finally
        {
            while (Interlocked.CompareExchange(ref busy, 0, 1) != 1)
            {
                throw new Exception("Releasing the mutex failed - but this should never happen");
            }
        }
    }
}


Of course this is a hack... did I just overlook a better way to do this using the standard framework?

Solution

A better alternative to the busy wait loop would be to use a Semaphore - in this case a SemaphoreSlim would probably be the most appropriate. Semaphores are not reentrant. This would simplify the implementation to:

struct DumbAsyncMutex
{
    private SemaphoreSlim _Semaphore = new SemaphoreSlim(1, 1);

    public async Task WithMutexAsync(Func t)
    {
        await _Semaphore.WaitAsync();

        try
        {
            await t();
        }
        finally
        {
            _Semaphore.Release(1);
        }
    }
}


The advantage is that it has async support and you can abandon the waiting by using cancellation tokens.

Code Snippets

struct DumbAsyncMutex
{
    private SemaphoreSlim _Semaphore = new SemaphoreSlim(1, 1);

    public async Task WithMutexAsync(Func<Task> t)
    {
        await _Semaphore.WaitAsync();

        try
        {
            await t();
        }
        finally
        {
            _Semaphore.Release(1);
        }
    }
}

Context

StackExchange Code Review Q#115836, answer score: 13

Revisions (0)

No revisions yet.