Beispiel #1
0
        private bool TryOffset(int releaseCount, out int previous, SemaphoreSlimState state)
        {
            var expected = Volatile.Read(ref _count);

            previous = expected;
            if (_maxCount.HasValue && expected + (long)releaseCount > (long)_maxCount)
            {
                throw new SemaphoreFullException();
            }

            var result = expected + releaseCount;

            if (result < 0)
            {
                return(false);
            }

            var found = Interlocked.CompareExchange(ref _count, result, expected);

            if (found != expected)
            {
                return(false);
            }

            SyncWaitHandle(state);
            return(true);
        }
Beispiel #2
0
        private void Awake(SemaphoreSlimState state)
        {
            var spinWait = new SpinWait();

            while (state.AsyncWaiters.TryTake(out var waiter))
            {
                if (waiter.Task.IsCompleted)
                {
                    // Skip - either canceled or timed out
                    continue;
                }

                if (TryOffset(-1, out _, state))
                {
                    waiter.SetResult(true);
                }
                else
                {
                    // Add it back
                    state.AsyncWaiters.Add(waiter);
                    break;
                }

                spinWait.SpinOnce();
            }
        }
Beispiel #3
0
        private void SyncWaitHandle(SemaphoreSlimState state)
        {
            var awake = false;

            if (Volatile.Read(ref _count) == 0 == state.CanEnter.IsSet && Interlocked.CompareExchange(ref _syncRoot, 1, 0) == 0)
            {
                try
                {
                    awake = SyncWaitHandleExtracted();
                }
                finally
                {
                    Volatile.Write(ref _syncRoot, 0);
                }
            }

            if (awake)
            {
                ThreadPool.QueueUserWorkItem(_ => Awake(state));
            }

            bool SyncWaitHandleExtracted()
            {
                int found;
                var canEnter = state.CanEnter;

                if ((found = Volatile.Read(ref _count)) == 0 != canEnter.IsSet)
                {
                    return(false);
                }

                if (found == 0)
                {
                    canEnter.Reset();
                }
                else
                {
                    canEnter.Set();
                    return(true);
                }

                return(false);
            }
        }