Пример #1
0
        private void ActivateNextQueueItemWithValidatedToken(int token)
        {
            // see if we can nudge the next waiter
            lock (_queue)
            {
                if (Volatile.Read(ref _token) != token)
                {
                    Throw.InvalidLockHolder();
                }

                try
                {
                    if (_queue.Count == 0)
                    {
                        Log($"no pending items to activate");
                        return;
                    }

                    // there's work to do; get a new token
                    Log($"pending items: {_queue.Count}");

                    // we're expecting to activate; get a new token speculatively
                    // (needs to be new so the old caller can't double-dispose and
                    // release someone else's lock)
                    Volatile.Write(ref _token, token = LockState.GetNextToken(token));

                    // try to give the new token to someone
                    while (_queue.Count != 0)
                    {
                        var next = DequeueInsideLock();
                        if (next.TrySetResult(token))
                        {
                            Log($"handed lock to {next}");
                            token = 0; // so we don't release the token
                            return;
                        }
                        else
                        {
                            Log($"lock rejected by {next}");
                        }
                    }
                }
                finally
                {
                    if (token != 0) // nobody actually wanted it; return it
                    {               // (this could be the original token, or a new speculative token)
                        Log("returning unwanted lock");
                        Volatile.Write(ref _token, LockState.ChangeState(token, LockState.Pending));
                    }
                    SetNextAsyncTimeoutInsideLock();
                }
            }
        }