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);
        }