Skip to main content
added 10 characters in body
Source Link
Stefan Steiger
  • 83k
  • 70
  • 405
  • 461
private static readonly System.Threading.SemaphoreSlim s_consoleSemaphore = new System.Threading.SemaphoreSlim(1, 1); internal static async System.Threading.Tasks.Task TestTestAsync() { // no lock possible because lock BLOCKS the thread when it waits // semaphore does not await using (AsyncLock consoleLocker = await AsyncLock.LockAsync(s_consoleSemaphore)) { await System.Console.Out.WriteLineAsync("inside the lock !"); } // End Using consoleLocker } // End Task TestTestAsync 
private static readonly System.Threading.SemaphoreSlim s_consoleSemaphore = new System.Threading.SemaphoreSlim(1, 1); internal static async System.Threading.Tasks.Task Test() { // no lock possible because lock BLOCKS the thread when it waits // semaphore does not await using (AsyncLock consoleLocker = await AsyncLock.LockAsync(s_consoleSemaphore)) { await System.Console.Out.WriteLineAsync("inside the lock !"); } // End Using consoleLocker } // End Task Test 
private static readonly System.Threading.SemaphoreSlim s_consoleSemaphore = new System.Threading.SemaphoreSlim(1, 1); internal static async System.Threading.Tasks.Task TestAsync() { // no lock possible because lock BLOCKS the thread when it waits // semaphore does not await using (AsyncLock consoleLocker = await AsyncLock.LockAsync(s_consoleSemaphore)) { await System.Console.Out.WriteLineAsync("inside the lock !"); } // End Using consoleLocker } // End Task TestAsync 
Source Link
Stefan Steiger
  • 83k
  • 70
  • 405
  • 461

I have my own class AsyncLock.
I made it IDisposable, so it can use a using-block.
(the unlock of the semaphore in the idispose ensures it will also be unlocked if there is an exception, without the need for try-finally)

namespace Test { public abstract class AsyncLock : System.IAsyncDisposable { private readonly System.Threading.SemaphoreSlim m_semaphore; protected AsyncLock(System.Threading.SemaphoreSlim semaphore) { this.m_semaphore = semaphore; } // End Constructor private class InternalAsyncSemaphoreSlimWrapper : AsyncLock { public InternalAsyncSemaphoreSlimWrapper(System.Threading.SemaphoreSlim semaphore) : base(semaphore) { } // End Constructor } // End Class InternalAsyncSemaphoreSlimWrapper private async System.Threading.Tasks.Task AcquireAsync() { await this.m_semaphore.WaitAsync(); // Asynchronously wait for the semaphore } // End Task AcquireAsync public static async System.Threading.Tasks.Task<AsyncLock> LockAsync(System.Threading.SemaphoreSlim semaphore) { InternalAsyncSemaphoreSlimWrapper wrapper = new InternalAsyncSemaphoreSlimWrapper(semaphore); await wrapper.AcquireAsync(); return wrapper; } // End Function LockAsync async System.Threading.Tasks.ValueTask System.IAsyncDisposable.DisposeAsync() { this.m_semaphore.Release(); // Release the semaphore when disposed await System.Threading.Tasks.Task.CompletedTask; } // End Task DisposeAsync internal static async System.Threading.Tasks.Task Test() { // private static readonly System.Threading.SemaphoreSlim s_consoleSemaphore = new System.Threading.SemaphoreSlim(1, 1); System.Threading.SemaphoreSlim s_consoleSemaphore = new System.Threading.SemaphoreSlim(1, 1); // because lock BLOCKS the thread when it waits await using (AsyncLock consoleLocker = await AsyncLock.LockAsync(s_consoleSemaphore)) { System.Console.WriteLine("inside the lock !"); } // End Using consoleLocker } // End Task Test } // End Class AsyncLock } // End Namespace 

This can then be used as follows

private static readonly System.Threading.SemaphoreSlim s_consoleSemaphore = new System.Threading.SemaphoreSlim(1, 1); internal static async System.Threading.Tasks.Task Test() { // no lock possible because lock BLOCKS the thread when it waits // semaphore does not await using (AsyncLock consoleLocker = await AsyncLock.LockAsync(s_consoleSemaphore)) { await System.Console.Out.WriteLineAsync("inside the lock !"); } // End Using consoleLocker } // End Task Test 

As you can see, new object() from lock is simply replaced with new SemaphoreSlim(1, 1)

The lock-statement for comparison:

private static readonly object s_consoleLock = new object(); internal static void Test() { // no lock possible because lock BLOCKS the thread when it waits // semaphore does not lock(s_consoleLock) { System.Console.WriteLine("inside the lock !"); } // End lock } // End Task Test