public async Task <bool> RunImpl(Func <Task> factory, Func <SerialExecutionBucket, Task> releaseBucketTask, CancellationToken cancellationToken, bool isAsync) { if (_released) { return(false); } Interlocked.Increment(ref this._waitingCount); try { using (isAsync ? await _bucketLockAsync.LockAsync(cancellationToken) : _bucketLockAsync.Lock(cancellationToken)) { if (_released) { return(false); } if (isAsync) { await factory(); } else { SyncTaskHelper.ValidateSyncTask(factory()); } return(true); } } finally { Interlocked.Decrement(ref this._waitingCount); if (!_released && _waitingCount == 0) { //no cancellation token used when releasing. using (isAsync ? await _bucketLockAsync.LockAsync() : _bucketLockAsync.Lock()) { if (!_released && _waitingCount == 0) { if (isAsync) { await releaseBucketTask(this); } else { SyncTaskHelper.ValidateSyncTask(releaseBucketTask(this)); } _released = true; } } } } }
private async Task RunImpl(Guid resource, Func <Task> factory, CancellationToken cancellationToken, bool isAsync) { SerialExecutionBucket bucket = null; bool run = false; while (!run) { using (isAsync ? await _lockAsync.LockAsync(cancellationToken) : _lockAsync.Lock(cancellationToken)) { bucket = _buckets.ContainsKey(resource) ? _buckets[resource] : (_buckets[resource] = SerialExecutionBucket.Create(resource)); } run = isAsync ? await bucket.RunImpl(factory, ReleaseBucketTask, cancellationToken, isAsync : isAsync) : SyncTaskHelper.ValidateSyncTask(bucket.RunImpl(factory, ReleaseBucketSync, cancellationToken, isAsync: isAsync)); } }
/// <summary> /// Provides execution of actions in a serial manner (one at a time) for each resource. Actions for different resources will run in parallel. /// The caller gets blocked till the action executes. /// </summary> /// <param name="resource">The resource id.</param> /// <param name="action">An action factory.</param> /// <param name="cancellationToken">(optional) Allows cancellation when waiting to run. Not after the action started.</param> public void Run(Guid resource, Action action, CancellationToken cancellationToken = default(CancellationToken)) { SyncTaskHelper.ValidateSyncTask(RunImpl(resource, WrapAction(action), cancellationToken, isAsync: false)); }