Simplifying and optimize a concurrent access
There is no sense in creating a task and waiting on it straight away. The following code is almost identical to your test method (almost - because tasks are created on a thread pool here):

[TestMethod]
public void RecoveryConcurrentTest()
{
    var tasks = Enumerable.Range(0, 10).Select(i =&gt; Task.Factory.StartNew(AutoRecover)).ToArray();

    Task.WaitAll(tasks);
}


Note that it doesn't actually test the fact that AutoRecover allows only one thread at a time, it just ensures that nothing fails when multiple threads call this method. There is no way in current design to detect it.

What I would suggest is to expose the fact of long process inside of AutoRecover by returning a Task that any thread can wait on:

[TestMethod]
public void RecoveryConcurrentTest()
{
    var tasks = Enumerable.Range(0, 10).Select(i =&gt; AutoRecoverAsync()).ToArray();

    Task.WaitAll(tasks);
}

private volatile Task _recoveryTask;
private readonly object _syncRoot = new object();

private async Task DoActualRecover()
{
    Trace.WriteLine("PROCESSING....");
    await Task.Delay(10000);
    Trace.WriteLine("PROCESSED....");
    _recoveryTask = null;
}

public Task AutoRecoverAsync()
{
    var recoveryTask = _recoveryTask;
    if (recoveryTask != null)
        return recoveryTask;

    lock (_syncRoot)
    {
        recoveryTask = _recoveryTask;
        if (recoveryTask != null)
            return recoveryTask;

        return _recoveryTask = DoActualRecover();
    }
}