private void CompleteWork(AsyncValueWorker worker) { LinkedListNode <AsyncValueWorker> left = worker.Node.Previous, right = worker.Node.Next; AsyncValueWorker toFree = left?.Value ?? right?.Value; List <AsyncValueWorker> related = null; // If a worker is still in the queue, it's still working. All children/siblings of the // current requester must be finished before it can move on. while (left != null || right != null) { if (ReferenceEquals(left?.Value.Requester, worker.Requester) || ReferenceEquals(right?.Value.Requester, worker.Requester)) { toFree = null; break; } if (ReferenceEquals(left?.Value.Requester, toFree?.Requester)) { if (related == null) { related = new List <AsyncValueWorker> (); } related.Add(left.Value); } if (ReferenceEquals(right?.Value.Requester, toFree?.Requester)) { if (related == null) { related = new List <AsyncValueWorker> (); } related.Add(right.Value); } left = left?.Previous; right = right?.Next; } this.workers.Remove(worker); if (toFree != null) { this.activeRequester = toFree.Requester; toFree.Completion.SetResult(toFree); if (related != null) { // Once the active requester changes, we need to sure its children/siblings are all allowed // same as if it had been the active one first. foreach (var w in related) { w.Completion.TrySetResult(w); } } } }
public Task <IDisposable> RequestAsyncWork(object requester) { var worker = new AsyncValueWorker(requester, this); this.workers.AddLast(worker.Node); if (this.workers.Count == 1 || ReferenceEquals(requester, this.activeRequester)) { worker.Completion.SetResult(worker); this.activeRequester = requester; } return(worker.Completion.Task); }