My use case is this:
- There is a long running process that I want to ensure is only ever running at most only a single time.
- Multiple consumers from different threads may wait on the calculation.
- If the process is not running, the first consumer triggers it.
Here is the code:
public class Worker {
private int _working;
private TaskCompletionSource? _tcs;
public async Task DoWorkAsync() {
var triggerWork = false;
if (Interlocked.CompareExchange(ref _working, 1, 0) == 0) {
triggerWork = true;
_tcs = new TaskCompletionSource();
}
if (!triggerWork) {
await _tcs!.Task;
/*
* Point of interest: previous worker might have just finished,
* and a new worker might have started - but that is ok because
* "DoWorkInternalAsync" is a transactioned operation.
*/
return;
}
await DoWorkInternalAsync();
_tcs!.SetResult();
_working = 0;
}
private async Task DoWorkInternalAsync() {
// Do work
}
}
I would like a review for my code for efficiency and correctness, and also I'd be happy to hear suggestions on how to do it more succinctly (perhaps with the use of a library or some BCL class I might have missed)
Thanks