Skip to content

Instantly share code, notes, and snippets.

@DvdKhl
Last active March 24, 2018 08:51
Show Gist options
  • Save DvdKhl/22beb783902fa7e676ba87b2dc50cb51 to your computer and use it in GitHub Desktop.
Save DvdKhl/22beb783902fa7e676ba87b2dc50cb51 to your computer and use it in GitHub Desktop.
Async/Await: Overlapping execution but only execute expensive task once per overlap
public class OverlapAsyncLock {
public class OverlapLock : IDisposable {
private bool isFirst;
private OverlapAsyncLock owner;
internal OverlapLock(bool isFirst, OverlapAsyncLock owner) {
this.isFirst = isFirst;
this.owner = owner;
}
public void Dispose() {
if (isFirst) owner.isActive = 0;
owner.semaphore.Release();
}
public bool IsFirst => isFirst;
}
private int isActive;
private readonly SemaphoreSlim semaphore = new SemaphoreSlim(1, 1);
private readonly OverlapLock first, other;
public OverlapAsyncLock() {
first = new OverlapLock(true, this);
other = new OverlapLock(false, this);
}
public async Task<OverlapLock> Lock() {
var localIsActive = Interlocked.CompareExchange(ref isActive, 1, 0);
await semaphore.WaitAsync();
return localIsActive == 0 ? first : other;
}
}
//Usage:
//private OverlapAsyncLock overlapAsyncLock = new OverlapAsyncLock();
//...
//using (var overlapLock = await overlapAsyncLock.Lock())
//if (overlapLock.IsFirst) { }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment