Mutex does not block async method

I have a code that looks a bit like that. I have a method do_it that does the work and uses some resources that must be protected by a mutex. To do it, I tried using a mutex before calling it, to force other tasks to block until the work is done. But the mutex does not block the second task, and both runs in paralell, I would like to know why, and what is the best way to do it.

using System;
using System.Threading;
using System.Threading.Tasks;

namespace teste_threads
{    
    class test_mutex
    {
        Mutex mut = new Mutex();

        public async Task first()
        {
            mut.WaitOne();
            await do_it();
            mut.ReleaseMutex();
        }

        public async Task second()
        {
            mut.WaitOne();
            await do_it();
            mut.ReleaseMutex();
        }

        public async Task do_it()
        {
            await Task.Run(() => doSomething());
        }

        private void doSomething()
        {
            Console.WriteLine("doSomething starting");
            Thread.Sleep(1000);
            Console.WriteLine("doSomething ending");
        }
    }

    class Program
    {
        static test_mutex test = new test_mutex();

        static void Main(string[] args)
        {
            test.first();
            Thread.Sleep(100);
            test.second();

            Thread.Sleep(3000);
        }      
    }
}

I was expecting that the output to this code would be:

doSomething starting
doSomething ending
doSomething starting
doSomething ending

but instead, I get:

doSomething starting
doSomething starting
doSomething ending
doSomething ending

that means the mutex is not blocking when second() is called. What is wrong with that mutex?

Answer

Mutexes – and other synchronous synchronization primitives – cannot be used with asynchronous code. You need asynchronous synchronization primitives.

There is one asynchronous synchronization primitive built-in: SemaphoreSlim, which can be used as an asynchronous mutex as such:

SemaphoreSlim mut = new SemaphoreSlim(1);

public async Task first()
{
  await mut.WaitAsync();
  try
  {
    await do_it();
  }
  finally
  {
    mut.Release();
  }
}

public async Task second()
{
  await mut.WaitAsync();
  try
  {
    await do_it();
  }
  finally
  {
    mut.Release();
  }
}