Beispiel #1
0
        /// <summary>
        /// Blocks the current thread until the next notification
        /// </summary>
        /// <param name="timeout">Tiemout in milliseconds</param>
        /// <param name="token">Cancellation token</param>
        /// <returns>True if the current thread successfully received a notification</returns>
        /// <exception cref="SynchronizationLockException">Lock is not acquired</exception>
        /// <exception cref="ObjectDisposedException">Waiter was disposed</exception>
        /// <exception cref="OperationCanceledException">Cancellation happened</exception>
        /// <exception cref="OperationInterruptedException">Waiting was interrupted by Dispose</exception>
        public bool Wait(int timeout, CancellationToken token)
        {
            if (!Monitor.IsEntered(this))
            {
                throw new SynchronizationLockException("Lock on the current SignalWaiter should be acquired");
            }
            if (_isDisposed)
            {
                throw new ObjectDisposedException(this.GetType().Name);
            }
            if (token.IsCancellationRequested)
            {
                throw new OperationCanceledException(token);
            }

            if (timeout < 0)
            {
                timeout = Timeout.Infinite;
            }


            CancellationTokenRegistration cancellationTokenRegistration = default(CancellationTokenRegistration);

            try
            {
                if (token.CanBeCanceled)
                {
                    cancellationTokenRegistration = CancellationTokenHelper.RegisterWithoutECIfPossible(token, _cancellationTokenCanceledEventHandler, this);
                }

                // Waiting for signal
                if (!Monitor.Wait(this, timeout))
                {
                    return(false);
                }

                // Check if cancellation or dispose was the reasons of the signal
                if (token.IsCancellationRequested)
                {
                    throw new OperationCanceledException(token);
                }
                if (_isDisposed)
                {
                    throw new OperationInterruptedException("Wait was interrupted by Dispose", new ObjectDisposedException(this.GetType().Name));
                }
            }
            finally
            {
                cancellationTokenRegistration.Dispose();
            }

            return(true);
        }
        /// <summary>
        /// Enter the lock on the current <see cref="ConditionVariable"/> object
        /// </summary>
        /// <param name="timeout">Total operation timeout</param>
        /// <param name="token">Cancellation token</param>
        /// <returns>Lock guard to work with 'using' statement</returns>
        /// <exception cref="ObjectDisposedException">ConditionVariable disposed</exception>
        /// <exception cref="OperationCanceledException">Cancellation requested</exception>
        /// <exception cref="SynchronizationLockException">externalLock is already acquired</exception>
        public ConditionVariableWaiter Enter(int timeout, CancellationToken token)
        {
            if (_isDisposed)
            {
                throw new ObjectDisposedException(nameof(ConditionVariable), $"ConditionVariable '{Name}' was disposed");
            }
            if (token.IsCancellationRequested)
            {
                throw new OperationCanceledException(token);
            }
            if (Monitor.IsEntered(_externalLock))
            {
                throw new SynchronizationLockException("Recursive lock is not supported");
            }

            uint startTime = 0;

            if (timeout > 0)
            {
                startTime = TimeoutHelper.GetTimestamp();
            }
            else if (timeout < -1)
            {
                timeout = Timeout.Infinite;
            }


            CancellationTokenRegistration cancellationTokenRegistration = default(CancellationTokenRegistration);

            if (token.CanBeCanceled)
            {
                try
                {
                    cancellationTokenRegistration = CancellationTokenHelper.RegisterWithoutECIfPossible(token, _cancellationTokenCanceledEventHandler, this);
                    Monitor.Enter(_externalLock); // Can be interrupted
                }
                catch
                {
                    cancellationTokenRegistration.Dispose();
                    throw;
                }
            }
            else
            {
                Monitor.Enter(_externalLock);
            }

            Interlocked.Increment(ref _waiterCount);
            return(new ConditionVariableWaiter(this, timeout, startTime, token, cancellationTokenRegistration));
        }
Beispiel #3
0
        private static void TestGeneratedRegister(CancellationToken token, int iter)
        {
            Action <object> act = new Action <object>(Callback);

            var sw = Stopwatch.StartNew();

            for (int i = 0; i < iter; i++)
            {
                using (var reg = CancellationTokenHelper.RegisterWithoutECIfPossible(token, act, null))
                {
                }
            }
            sw.Stop();
            Console.WriteLine($"Generated register: {sw.ElapsedMilliseconds}ms");
        }
Beispiel #4
0
        /// <summary>
        /// Enter the lock on the current <see cref="MonitorObject"/> object
        /// </summary>
        /// <param name="timeout">Total operation timeout</param>
        /// <param name="token">Cancellation token</param>
        /// <returns>Lock guard to work with 'using' statement</returns>
        /// <exception cref="ObjectDisposedException">MonitorObject disposed</exception>
        /// <exception cref="OperationCanceledException">Cancellation requested</exception>
        public MonitorWaiter Enter(int timeout, CancellationToken token)
        {
            if (_isDisposed)
            {
                throw new ObjectDisposedException(nameof(MonitorObject), $"MonitorObject '{Name}' was disposed");
            }
            if (token.IsCancellationRequested)
            {
                throw new OperationCanceledException(token);
            }

            uint startTime = 0;

            if (timeout > 0)
            {
                startTime = TimeoutHelper.GetTimestamp();
            }
            else if (timeout < -1)
            {
                timeout = Timeout.Infinite;
            }


            CancellationTokenRegistration cancellationTokenRegistration = default(CancellationTokenRegistration);

            if (token.CanBeCanceled)
            {
                try
                {
                    cancellationTokenRegistration = CancellationTokenHelper.RegisterWithoutECIfPossible(token, _cancellationTokenCanceledEventHandler, this);
                    Monitor.Enter(this); // Can be interrupted
                }
                catch
                {
                    cancellationTokenRegistration.Dispose();
                    throw;
                }
            }
            else
            {
                Monitor.Enter(this);
            }

            Interlocked.Increment(ref _waiterCount);
            return(new MonitorWaiter(this, timeout, startTime, token, cancellationTokenRegistration));
        }
Beispiel #5
0
        public void RegisterWithoutECTest()
        {
            var originalContext = SynchronizationContext.Current;
            var syncContext     = new CustomSyncContext();

            try
            {
                CancellationTokenSource tokenSource = new CancellationTokenSource();
                CancellationToken       token       = tokenSource.Token;

                AtomicBool isNoExecutionContext = new AtomicBool(false);

                using (CancellationTokenHelper.RegisterWithoutECIfPossible(token, (st) =>
                {
                    isNoExecutionContext.Value = SynchronizationContext.Current == null;
                }, null))
                {
                    Barrier barrier  = new Barrier(2);
                    Barrier barrier2 = new Barrier(2);

                    Task.Run(() =>
                    {
                        barrier.SignalAndWait();
                        barrier2.SignalAndWait();
                        tokenSource.Cancel();
                    });

                    barrier.SignalAndWait();
                    SynchronizationContext.SetSynchronizationContext(syncContext);
                    barrier2.SignalAndWait();
                    TimingAssert.IsTrue(10000, isNoExecutionContext, "isNoExecutionContext");
                }
            }
            finally
            {
                SynchronizationContext.SetSynchronizationContext(originalContext);
            }
        }
Beispiel #6
0
        /// <summary>
        /// Slow path
        /// </summary>
        private bool WaitSlowPath <TState>(WaitPredicate <TState> predicate, TState state, uint startTime, int timeout, CancellationToken token)
        {
            if (token.IsCancellationRequested)
            {
                throw new OperationCanceledException(token);
            }

            if (timeout < 0)
            {
                timeout = Timeout.Infinite;
            }

            if (timeout > 0 && TimeoutHelper.UpdateTimeout(startTime, timeout) <= 0) // Predicate estimation took too much time
            {
                return(false);
            }

            CancellationTokenRegistration cancellationTokenRegistration = default(CancellationTokenRegistration);
            bool internalLockTaken = false;
            bool externalLockTaken = true;

            try
            {
                if (token.CanBeCanceled)
                {
                    cancellationTokenRegistration = CancellationTokenHelper.RegisterWithoutECIfPossible(token, _cancellationTokenCanceledEventHandler, this);
                }

                try { }
                finally
                {
                    Monitor.Enter(_internalLock, ref internalLockTaken);
                    TurboContract.Assert(internalLockTaken, conditionString: "internalLockTaken");
                    _waitCount++;
                }

                if (WaitUntilPredicate(ref internalLockTaken, ref externalLockTaken, predicate, state, startTime, timeout, token))
                {
                    return(true);
                }

                if (token.IsCancellationRequested)
                {
                    throw new OperationCanceledException(token);
                }

                if (_isDisposed)
                {
                    throw new OperationInterruptedException("Wait was interrupted by Dispose", new ObjectDisposedException(this.GetType().Name));
                }
            }
            finally
            {
                if (internalLockTaken)
                {
                    _waitCount--;
                    TurboContract.Assert(_waitCount >= 0, conditionString: "_waitCount >= 0");
                    Monitor.Exit(_internalLock);
                }

                EnterLock(_externalLock, ref externalLockTaken);

                cancellationTokenRegistration.Dispose();
            }

            // Final check for predicate
            return(predicate(state));
        }
Beispiel #7
0
        /// <summary>
        /// Blocks the current thread until the next notification
        /// </summary>
        /// <param name="timeout">Tiemout in milliseconds</param>
        /// <param name="token">Cancellation token</param>
        /// <returns>True if the current thread successfully received a notification</returns>
        /// <exception cref="SynchronizationLockException">externalLock is not acquired or acquired recursively</exception>
        /// <exception cref="ObjectDisposedException">ConditionVariable was disposed</exception>
        /// <exception cref="OperationCanceledException">Cancellation happened</exception>
        /// <exception cref="OperationInterruptedException">Waiting was interrupted by Dispose</exception>
        public bool Wait(int timeout, CancellationToken token)
        {
            if (!Monitor.IsEntered(_externalLock))
            {
                throw new SynchronizationLockException("External lock should be acquired");
            }
            if (_isDisposed)
            {
                throw new ObjectDisposedException(this.GetType().Name);
            }
            if (token.IsCancellationRequested)
            {
                throw new OperationCanceledException(token);
            }

            uint startTime = 0;

            if (timeout > 0)
            {
                startTime = TimeoutHelper.GetTimestamp();
            }
            else if (timeout < 0)
            {
                timeout = Timeout.Infinite;
            }


            CancellationTokenRegistration cancellationTokenRegistration = default(CancellationTokenRegistration);
            bool internalLockTaken = false;
            bool externalLockTaken = true;

            try
            {
                if (token.CanBeCanceled)
                {
                    cancellationTokenRegistration = CancellationTokenHelper.RegisterWithoutECIfPossible(token, _cancellationTokenCanceledEventHandler, this);
                }

                try { }
                finally
                {
                    Monitor.Enter(_internalLock, ref internalLockTaken);
                    TurboContract.Assert(internalLockTaken, conditionString: "internalLockTaken");
                    _waitCount++;
                }

                // Check if cancelled or disposed after entering the lock
                if (token.IsCancellationRequested)
                {
                    throw new OperationCanceledException(token);
                }
                if (_isDisposed)
                {
                    throw new OperationInterruptedException("Wait was interrupted by Dispose", new ObjectDisposedException(this.GetType().Name));
                }

                // Calculate remaining timeout
                int remainingWaitMilliseconds = Timeout.Infinite;
                if (timeout != Timeout.Infinite)
                {
                    remainingWaitMilliseconds = TimeoutHelper.UpdateTimeout(startTime, timeout);
                    if (remainingWaitMilliseconds <= 0)
                    {
                        return(false);
                    }
                }

                // Exit external lock right before Wait
                ExitLock(_externalLock, ref externalLockTaken);

                if (Monitor.IsEntered(_externalLock)) // Sanity check
                {
                    throw new SynchronizationLockException("Recursive lock is not supported");
                }

                // Waiting for signal
                if (!Monitor.Wait(_internalLock, remainingWaitMilliseconds))
                {
                    return(false);
                }

                // Check if cancellation or dispose was the reasons of the signal
                if (token.IsCancellationRequested)
                {
                    throw new OperationCanceledException(token);
                }
                if (_isDisposed)
                {
                    throw new OperationInterruptedException("Wait was interrupted by Dispose", new ObjectDisposedException(this.GetType().Name));
                }
            }
            finally
            {
                if (internalLockTaken)
                {
                    _waitCount--;
                    TurboContract.Assert(_waitCount >= 0, conditionString: "_waitCount >= 0");
                    Monitor.Exit(_internalLock);
                }

                EnterLock(_externalLock, ref externalLockTaken);

                cancellationTokenRegistration.Dispose();
            }

            return(true);
        }
Beispiel #8
0
        /// <summary>
        /// Blocks the current thread until predicate estimates as True
        /// </summary>
        /// <typeparam name="TState">Type of the state object</typeparam>
        /// <param name="predicate">Predicate that should return True to complete waiting</param>
        /// <param name="state">State object for the predicate</param>
        /// <param name="timeout">Tiemout in milliseconds</param>
        /// <param name="token">Cancellation token</param>
        /// <returns>True if predicate evaluates to True</returns>
        /// <exception cref="ArgumentNullException">predicate is null</exception>
        /// <exception cref="SynchronizationLockException">Lock is not acquired</exception>
        /// <exception cref="ObjectDisposedException">Waiter was disposed</exception>
        /// <exception cref="OperationCanceledException">Cancellation happened</exception>
        /// <exception cref="OperationInterruptedException">Waiting was interrupted by Dispose</exception>
        public bool Wait <TState>(WaitPredicate <TState> predicate, TState state, int timeout, CancellationToken token)
        {
            if (predicate == null)
            {
                throw new ArgumentNullException(nameof(predicate));
            }
            if (!Monitor.IsEntered(this))
            {
                throw new SynchronizationLockException("External lock should be acquired");
            }
            if (_isDisposed)
            {
                throw new ObjectDisposedException(this.GetType().Name);
            }
            if (token.IsCancellationRequested)
            {
                throw new OperationCanceledException(token);
            }

            uint startTime = 0;

            if (timeout > 0)
            {
                startTime = TimeoutHelper.GetTimestamp();
            }
            else if (timeout < -1)
            {
                timeout = Timeout.Infinite;
            }

            if (predicate(state))
            {
                return(true);
            }

            if (timeout == 0)
            {
                return(false);
            }

            if (timeout > 0 && TimeoutHelper.UpdateTimeout(startTime, timeout) <= 0) // Predicate estimation took too much time
            {
                return(false);
            }

            CancellationTokenRegistration cancellationTokenRegistration = default(CancellationTokenRegistration);

            try
            {
                if (token.CanBeCanceled)
                {
                    cancellationTokenRegistration = CancellationTokenHelper.RegisterWithoutECIfPossible(token, _cancellationTokenCanceledEventHandler, this);
                }

                if (WaitUntilPredicate(predicate, state, startTime, timeout, token))
                {
                    return(true);
                }

                if (token.IsCancellationRequested)
                {
                    throw new OperationCanceledException(token);
                }

                if (_isDisposed)
                {
                    throw new OperationInterruptedException("Wait was interrupted by Dispose", new ObjectDisposedException(this.GetType().Name));
                }
            }
            finally
            {
                cancellationTokenRegistration.Dispose();
            }

            // Final check for predicate
            return(predicate(state));
        }
Beispiel #9
0
 /// <summary>
 /// Helper method to register notification for token cancellation
 /// </summary>
 /// <param name="token">Cancellation token</param>
 /// <returns>Registration info</returns>
 internal CancellationTokenRegistration RegisterNotificationOnCancellation(CancellationToken token)
 {
     return(CancellationTokenHelper.RegisterWithoutECIfPossible(token, _cancellationTokenCanceledEventHandler, this));
 }
Beispiel #10
0
        /// <summary>
        /// Blocks the current thread until it can enter the semaphore
        /// </summary>
        /// <param name="timeout">Tiemout in milliseconds</param>
        /// <param name="token">Cancellation token</param>
        /// <param name="throwOnCancellation">Whether the OperationCanceledException should be thrown if cancellation happened</param>
        /// <returns>True if the current thread successfully entered the semaphore</returns>
        internal bool Wait(int timeout, CancellationToken token, bool throwOnCancellation)
        {
            if (_isDisposed)
            {
                throw new ObjectDisposedException(this.GetType().Name);
            }

            if (token.IsCancellationRequested)
            {
                if (throwOnCancellation)
                {
                    throw new OperationCanceledException(token);
                }

                return(false);
            }

            // Делаем захват
            if (TryTakeLockFree())
            {
                return(true);
            }

            // Early exit: nothing to wait
            if (timeout == 0 && _waitCount >= _currentCountForWait)
            {
                return(false);
            }

            uint startTime = 0;

            if (timeout > 0)
            {
                startTime = TimeoutHelper.GetTimestamp();
            }
            else if (timeout < -1)
            {
                timeout = Timeout.Infinite;
            }

            // Ждём появления (лучше активно подождать, чем входить в lock)
            if (_waitCount >= _currentCountForWait)
            {
                if (timeout == 0) // Редкая ситуация. При нулевом таймауте нам нечего ловить
                {
                    return(false);
                }

                int spinNumber          = _processorCount > 1 ? 0 : SPIN_YIELD_THRESHOLD; // Пропускаем активное ожидание, если только одно ядро доступно
                int currentCountLocFree = _currentCountLockFree;
                while (spinNumber < SPIN_YIELD_THRESHOLD + 8)
                {
                    if (currentCountLocFree > 0 && Interlocked.CompareExchange(ref _currentCountLockFree, currentCountLocFree - 1, currentCountLocFree) == currentCountLocFree)
                    {
                        return(true);
                    }

                    SpinOnce(spinNumber);
                    if (spinNumber < SPIN_YIELD_THRESHOLD && _waitCount > _currentCountForWait + 2) // Жгём CPU только если немного потоков в ожидании. Иначе лучше на Thread.Yield переходить
                    {
                        spinNumber = SPIN_YIELD_THRESHOLD;
                    }
                    else
                    {
                        spinNumber++;
                    }

                    currentCountLocFree = _currentCountLockFree;
                }

                // Пробуем захватить ещё раз
                if (currentCountLocFree > 0 && Interlocked.CompareExchange(ref _currentCountLockFree, currentCountLocFree - 1, currentCountLocFree) == currentCountLocFree)
                {
                    return(true);
                }
            }

            // Вынуждены уходить в lock
            CancellationTokenRegistration cancellationTokenRegistration = default(CancellationTokenRegistration);
            bool lockTaken = false;

            try
            {
                if (token.CanBeCanceled)
                {
                    cancellationTokenRegistration = CancellationTokenHelper.RegisterWithoutECIfPossible(token, _cancellationTokenCanceledEventHandler, this);
                }

                try { }
                finally
                {
                    Monitor.Enter(_lockObj, ref lockTaken);
                    TurboContract.Assert(lockTaken, conditionString: "lockTaken");
                    Interlocked.Increment(ref _waitCount); // Release должен увидеть наше появление
                }

                // Пробуем забрать из _currentCountForWait
                if (_currentCountForWait > 0)
                {
                    _currentCountForWait--;
                    return(true);
                }

                // Пока входили в lock могли добавится значения в _currentCountLocFree
                if (TryTakeLockFree())
                {
                    return(true);
                }

                if (timeout == 0)
                {
                    return(false);
                }

                // Ожидаем появления элементов и забираем сразу
                if (WaitUntilCountOrTimeoutAndTake(timeout, startTime, token))
                {
                    return(true);
                }

                if (token.IsCancellationRequested)
                {
                    if (throwOnCancellation)
                    {
                        throw new OperationCanceledException(token);
                    }

                    return(false);
                }

                if (_isDisposed)
                {
                    throw new OperationInterruptedException("Semaphore wait was interrupted by Dispose", new ObjectDisposedException(this.GetType().Name));
                }
            }
            finally
            {
                if (lockTaken)
                {
                    _waitCount--;
                    TurboContract.Assert(_waitCount >= 0, conditionString: "_waitCount >= 0");
                    Monitor.Exit(_lockObj);
                }

                cancellationTokenRegistration.Dispose();
            }

            return(false);
        }
Beispiel #11
0
        /// <summary>
        /// Blocks the current thread if it is required
        /// </summary>
        /// <param name="timeout">Waiting timeout in milliseconds</param>
        /// <param name="token">Cancellation token</param>
        /// <returns>True if the current thread successfully passed the <see cref="PartialThreadBlocker"/> (false - exited by timeout)</returns>
        public bool Wait(int timeout, CancellationToken token)
        {
            token.ThrowIfCancellationRequested();
            if (timeout < 0)
            {
                timeout = Timeout.Infinite;
            }

            if (_realWaiterCount >= _expectedWaiterCount)
            {
                return(true);
            }

            if (timeout == 0)
            {
                return(false);
            }

            uint startTime   = 0;
            int  currentTime = Timeout.Infinite;

            if (timeout != Timeout.Infinite)
            {
                startTime = TimeoutHelper.GetTimestamp();
            }

            for (int i = 0; i < 10; i++)
            {
                if (_realWaiterCount >= _expectedWaiterCount)
                {
                    return(true);
                }

                if (i == 5)
                {
                    Thread.Yield();
                }
                else
                {
                    Thread.SpinWait(150 + (4 << i));
                }
            }


            using (CancellationTokenHelper.RegisterWithoutECIfPossible(token, _cancellationTokenCanceledEventHandler, this))
            {
                lock (_lockObj)
                {
                    if (_realWaiterCount < _expectedWaiterCount)
                    {
                        try
                        {
                            _realWaiterCount++;

                            while (_realWaiterCount <= _expectedWaiterCount)
                            {
                                token.ThrowIfCancellationRequested();

                                if (timeout != Timeout.Infinite)
                                {
                                    currentTime = TimeoutHelper.UpdateTimeout(startTime, timeout);
                                    if (currentTime <= 0)
                                    {
                                        return(false);
                                    }
                                }

                                if (!Monitor.Wait(_lockObj, currentTime))
                                {
                                    return(false);
                                }
                            }
                        }
                        finally
                        {
                            _realWaiterCount--;
                        }
                    }
                }
            }
            return(true);
        }
Beispiel #12
0
        /// <summary>
        /// Blocks the current thread until it can enter the semaphore
        /// </summary>
        /// <param name="timeout">Tiemout in milliseconds</param>
        /// <param name="token">Cancellation token</param>
        /// <param name="throwOnCancellation">Whether the OperationCanceledException should be thrown if cancellation happened</param>
        /// <returns>True if the current thread successfully entered the semaphore</returns>
        internal bool Wait(int timeout, CancellationToken token, bool throwOnCancellation)
        {
            if (_isDisposed)
            {
                throw new ObjectDisposedException(this.GetType().Name);
            }

            if (token.IsCancellationRequested)
            {
                if (throwOnCancellation)
                {
                    throw new OperationCanceledException(token);
                }

                return(false);
            }

            // Делаем захват
            if (TryTakeLockFree())
            {
                return(true);
            }

            // Early exit: nothing to wait
            if (timeout == 0 && _waitCount >= _currentCountForWait)
            {
                return(false);
            }

            uint startTime = 0;

            if (timeout > 0)
            {
                startTime = TimeoutHelper.GetTimestamp();
            }
            else if (timeout < -1)
            {
                timeout = Timeout.Infinite;
            }


            // Ждём появления (лучше активно подождать, чем входить в lock)
            if (_processorCount > 1)
            {
                int currentCountLocFree = _currentCountLockFree;
                if (_waitCount >= _currentCountForWait && _waitCount <= _currentCountForWait + 2)
                {
                    for (int i = 0; i < 8; i++)
                    {
                        if (currentCountLocFree > 0 && Interlocked.CompareExchange(ref _currentCountLockFree, currentCountLocFree - 1, currentCountLocFree) == currentCountLocFree)
                        {
                            return(true);
                        }

                        Thread.SpinWait(150 + 16 * i);
                        currentCountLocFree = _currentCountLockFree;
                    }
                }

                // Пробуем захватить ещё раз
                if (currentCountLocFree > 0 && Interlocked.CompareExchange(ref _currentCountLockFree, currentCountLocFree - 1, currentCountLocFree) == currentCountLocFree)
                {
                    return(true);
                }
            }


            if (timeout == 0 && _waitCount >= _currentCountForWait)
            {
                return(false);
            }

            if (_waitCount >= _currentCountForWait)
            {
                Thread.Yield();

                int currentCountLocFree = _currentCountLockFree;
                if (currentCountLocFree > 0 && Interlocked.CompareExchange(ref _currentCountLockFree, currentCountLocFree - 1, currentCountLocFree) == currentCountLocFree)
                {
                    return(true);
                }
            }

            // Вынуждены уходить в lock
            CancellationTokenRegistration cancellationTokenRegistration = default(CancellationTokenRegistration);
            bool lockTaken = false;

            try
            {
                if (token.CanBeCanceled)
                {
                    cancellationTokenRegistration = CancellationTokenHelper.RegisterWithoutECIfPossible(token, _cancellationTokenCanceledEventHandler, this);
                }

                try { }
                finally
                {
                    Monitor.Enter(_lockObj, ref lockTaken);
                    TurboContract.Assert(lockTaken, conditionString: "lockTaken");
                    Interlocked.Increment(ref _waitCount); // Release должен увидеть наше появление
                }

                // Пробуем забрать из _currentCountForWait
                if (_currentCountForWait > 0)
                {
                    _currentCountForWait--;
                    return(true);
                }

                // Пока входили в lock могли добавится значения в _currentCountLocFree
                if (TryTakeLockFree())
                {
                    return(true);
                }

                if (timeout == 0)
                {
                    return(false);
                }

                // Ожидаем появления элементов и забираем сразу
                if (WaitUntilCountOrTimeoutAndTake(timeout, startTime, token))
                {
                    return(true);
                }

                if (token.IsCancellationRequested)
                {
                    if (throwOnCancellation)
                    {
                        throw new OperationCanceledException(token);
                    }

                    return(false);
                }

                if (_isDisposed)
                {
                    throw new OperationInterruptedException("Semaphore wait was interrupted by Dispose", new ObjectDisposedException(this.GetType().Name));
                }
            }
            finally
            {
                if (lockTaken)
                {
                    _waitCount--;
                    TurboContract.Assert(_waitCount >= 0, conditionString: "_waitCount >= 0");
                    Monitor.Exit(_lockObj);
                }

                cancellationTokenRegistration.Dispose();
            }

            return(false);
        }