Skip to main content
The points of view of both participants of the comments are taken into account.
Source Link
Serg
  • 7.6k
  • 4
  • 43
  • 58

Basic Version



Extended Version


A version of the LockAsync method that claims to be completely deadlock-safe, can be found in (from the 4th revision of this answer (bysuggested by Jez).

using System; using System.Threading; using System.Threading.Tasks; public class SemaphoreLocker { private readonly SemaphoreSlim _semaphore = new SemaphoreSlim(1, 1); public async Task LockAsync(Func<Task> worker) { var isTaken = false; try { do { try { } finally { isTaken = await _semaphore.WaitAsync(TimeSpan.FromSeconds(1)); } } while (!isTaken); await worker(); } finally { if (isTaken) { _semaphore.Release(); } } } // overloading variant for non-void methods with return type (generic T) public async Task<T> LockAsync<T>(Func<Task<T>> worker) { var isTaken = false; try { do { try { } finally { isTaken = await _semaphore.WaitAsync(TimeSpan.FromSeconds(1)); } } while (!isTaken); return await worker(); } finally { if (isTaken) { _semaphore.Release(); } } } } 

Usage:

public class Test { private static readonly SemaphoreLocker _locker = new SemaphoreLocker(); public async Task DoTest() { await _locker.LockAsync(async () => { // [async] calls can be used within this block // to handle a resource by one thread. }); // OR var result = await _locker.LockAsync(async () => { // [async] calls can be used within this block // to handle a resource by one thread. }); } } 

A version of the LockAsync method that claims to be completely deadlock-safe, can be found in the 4th revision of this answer (by Jez).


Basic Version



Extended Version


A version of the LockAsync method that claims to be completely deadlock-safe (from the 4th revision suggested by Jez).

using System; using System.Threading; using System.Threading.Tasks; public class SemaphoreLocker { private readonly SemaphoreSlim _semaphore = new SemaphoreSlim(1, 1); public async Task LockAsync(Func<Task> worker) { var isTaken = false; try { do { try { } finally { isTaken = await _semaphore.WaitAsync(TimeSpan.FromSeconds(1)); } } while (!isTaken); await worker(); } finally { if (isTaken) { _semaphore.Release(); } } } // overloading variant for non-void methods with return type (generic T) public async Task<T> LockAsync<T>(Func<Task<T>> worker) { var isTaken = false; try { do { try { } finally { isTaken = await _semaphore.WaitAsync(TimeSpan.FromSeconds(1)); } } while (!isTaken); return await worker(); } finally { if (isTaken) { _semaphore.Release(); } } } } 

Usage:

public class Test { private static readonly SemaphoreLocker _locker = new SemaphoreLocker(); public async Task DoTest() { await _locker.LockAsync(async () => { // [async] calls can be used within this block // to handle a resource by one thread. }); // OR var result = await _locker.LockAsync(async () => { // [async] calls can be used within this block // to handle a resource by one thread. }); } } 
Added a link to Jez's version of LockAsync
Source Link
Theodor Zoulias
  • 46.1k
  • 8
  • 112
  • 155

This is just an extension to this answer by user1639030.

using System; using System.Threading; using System.Threading.Tasks; public class SemaphoreLocker { private readonly SemaphoreSlim _semaphore = new SemaphoreSlim(1, 1); public async Task LockAsync(Func<Task> worker) { await _semaphore.WaitAsync(); try { await worker(); } finally { _semaphore.Release(); } } // overloading variant for non-void methods with return type (generic T) public async Task<T> LockAsync<T>(Func<Task<T>> worker) { await _semaphore.WaitAsync(); try { return await worker(); } finally { _semaphore.Release(); } } } 

Usage:

public class Test { private static readonly SemaphoreLocker _locker = new SemaphoreLocker(); public async Task DoTest() { await _locker.LockAsync(async () => { // [async] calls can be used within this block // to handle a resource by one thread. }); // OR var result = await _locker.LockAsync(async () => { // [async] calls can be used within this block // to handle a resource by one thread. }); } } 

A version of the LockAsync method that claims to be completely deadlock-safe, can be found in the 4th revision of this answer (by Jez).

This is just an extension to this answer by user1639030.

using System; using System.Threading; using System.Threading.Tasks; public class SemaphoreLocker { private readonly SemaphoreSlim _semaphore = new SemaphoreSlim(1, 1); public async Task LockAsync(Func<Task> worker) { await _semaphore.WaitAsync(); try { await worker(); } finally { _semaphore.Release(); } } // overloading variant for non-void methods with return type (generic T) public async Task<T> LockAsync<T>(Func<Task<T>> worker) { await _semaphore.WaitAsync(); try { return await worker(); } finally { _semaphore.Release(); } } } 

Usage:

public class Test { private static readonly SemaphoreLocker _locker = new SemaphoreLocker(); public async Task DoTest() { await _locker.LockAsync(async () => { // [async] calls can be used within this block // to handle a resource by one thread. }); // OR var result = await _locker.LockAsync(async () => { // [async] calls can be used within this block // to handle a resource by one thread. }); } } 

This is just an extension to this answer by user1639030.

using System; using System.Threading; using System.Threading.Tasks; public class SemaphoreLocker { private readonly SemaphoreSlim _semaphore = new SemaphoreSlim(1, 1); public async Task LockAsync(Func<Task> worker) { await _semaphore.WaitAsync(); try { await worker(); } finally { _semaphore.Release(); } } // overloading variant for non-void methods with return type (generic T) public async Task<T> LockAsync<T>(Func<Task<T>> worker) { await _semaphore.WaitAsync(); try { return await worker(); } finally { _semaphore.Release(); } } } 

Usage:

public class Test { private static readonly SemaphoreLocker _locker = new SemaphoreLocker(); public async Task DoTest() { await _locker.LockAsync(async () => { // [async] calls can be used within this block // to handle a resource by one thread. }); // OR var result = await _locker.LockAsync(async () => { // [async] calls can be used within this block // to handle a resource by one thread. }); } } 

A version of the LockAsync method that claims to be completely deadlock-safe, can be found in the 4th revision of this answer (by Jez).

Mentioned the author of the related answer. Reduced emphasis.
Source Link
Theodor Zoulias
  • 46.1k
  • 8
  • 112
  • 155

This is just an extension to this answer. This is just an extension to this answer by user1639030.

using System; using System.Threading; using System.Threading.Tasks; public class SemaphoreLocker { private readonly SemaphoreSlim _semaphore = new SemaphoreSlim(1, 1); public async Task LockAsync(Func<Task> worker) { await _semaphore.WaitAsync(); try { await worker(); } finally { _semaphore.Release(); } } // overloading variant for non-void methods with return type (generic T) public async Task<T> LockAsync<T>(Func<Task<T>> worker) { await _semaphore.WaitAsync(); try { return await worker(); } finally { _semaphore.Release(); } } } 

Usage:

public class Test { private static readonly SemaphoreLocker _locker = new SemaphoreLocker(); public async Task DoTest() { await _locker.LockAsync(async () => { // [async] calls can be used within this block // to handle a resource by one thread. }); // OR var result = await _locker.LockAsync(async () => { // [async] calls can be used within this block // to handle a resource by one thread. }); } } 

This is just an extension to this answer.

using System; using System.Threading; using System.Threading.Tasks; public class SemaphoreLocker { private readonly SemaphoreSlim _semaphore = new SemaphoreSlim(1, 1); public async Task LockAsync(Func<Task> worker) { await _semaphore.WaitAsync(); try { await worker(); } finally { _semaphore.Release(); } } // overloading variant for non-void methods with return type (generic T) public async Task<T> LockAsync<T>(Func<Task<T>> worker) { await _semaphore.WaitAsync(); try { return await worker(); } finally { _semaphore.Release(); } } } 

Usage:

public class Test { private static readonly SemaphoreLocker _locker = new SemaphoreLocker(); public async Task DoTest() { await _locker.LockAsync(async () => { // [async] calls can be used within this block // to handle a resource by one thread. }); // OR var result = await _locker.LockAsync(async () => { // [async] calls can be used within this block // to handle a resource by one thread. }); } } 

This is just an extension to this answer by user1639030.

using System; using System.Threading; using System.Threading.Tasks; public class SemaphoreLocker { private readonly SemaphoreSlim _semaphore = new SemaphoreSlim(1, 1); public async Task LockAsync(Func<Task> worker) { await _semaphore.WaitAsync(); try { await worker(); } finally { _semaphore.Release(); } } // overloading variant for non-void methods with return type (generic T) public async Task<T> LockAsync<T>(Func<Task<T>> worker) { await _semaphore.WaitAsync(); try { return await worker(); } finally { _semaphore.Release(); } } } 

Usage:

public class Test { private static readonly SemaphoreLocker _locker = new SemaphoreLocker(); public async Task DoTest() { await _locker.LockAsync(async () => { // [async] calls can be used within this block // to handle a resource by one thread. }); // OR var result = await _locker.LockAsync(async () => { // [async] calls can be used within this block // to handle a resource by one thread. }); } } 
Rollback to Revision 3
Source Link
Theodor Zoulias
  • 46.1k
  • 8
  • 112
  • 155
Loading
Made locker completely deadlock-safe
Source Link
Jez
  • 30.5k
  • 37
  • 155
  • 261
Loading
minor code syntax cleanup.
Source Link
Jesse C. Slicer
  • 20.2k
  • 5
  • 74
  • 91
Loading
Added overloading function that can also retrieve the returned result from the async method.
Source Link
Loading
Source Link
Serg
  • 7.6k
  • 4
  • 43
  • 58
Loading