Does SemaphoreSlim's timeout defeat its own purpose?

You need to check the return value of the wait. The Timeout based wait will try for 2 seconds to take the mutex then return. You need to check if the return value is true (i.e you have the mutex) or not.

Edit: Also keep in mind that the timeout based wait will return immediately if the semaphore is available, so you cant use this to prevent an infinite loop in the code via this technique.

private readonly SemaphoreSlim _mutex = new SemaphoreSlim(1);
void Main()
{

    Task.Run(()=>DelayAndIncrementAsync());
    Task.Run(()=>DelayAndIncrementAsync());
}
public   void  DelayAndIncrementAsync()
{
    if (_mutex.Wait(2000))
    {
        try
        {
            Console.WriteLine(0);
            Thread.Sleep(TimeSpan.FromSeconds(5));
            Console.WriteLine(1);
        }    
        finally
        {
            _mutex.Release();
        }
    } else {
        //oh noes I don't have the mutex
    }
}

Your misconception is that there is an implicit "mutex zone" which is not defined by you.

The overload of Wait which you are using returns a boolean value which tells you whether or not the mutex was successfully entered.

What you are doing in your example is entering the critical zone whether or not the thread has acquired the mutex, making it redundant.

Generally, you would want to use this overload in any situation where you want to try to enter a mutex but also have a fallback strategy in case that it is not currently possible to acquire the mutex within the allotted time.