Ejemplo n.º 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.RegisterWithoutEC(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);
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Enter the lock on the current <see cref="ConditionVariableAlt"/> 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 ConditionVariableAltWaiter Enter(int timeout, CancellationToken token)
        {
            if (_isDisposed)
            {
                throw new ObjectDisposedException(nameof(ConditionVariableAlt), $"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.RegisterWithoutEC(token, _cancellationTokenCanceledEventHandler, this);
                    Monitor.Enter(_externalLock); // Can be interrupted
                }
                catch
                {
                    cancellationTokenRegistration.Dispose();
                    throw;
                }
            }
            else
            {
                Monitor.Enter(_externalLock);
            }

            Interlocked.Increment(ref _waiterCount);
            return(new ConditionVariableAltWaiter(this, timeout, startTime, token, cancellationTokenRegistration));
        }
Ejemplo n.º 3
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.RegisterWithoutEC(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);
        }
Ejemplo n.º 4
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.RegisterWithoutEC(token, _cancellationTokenCanceledEventHandler, this);
                }

                try { }
                finally
                {
                    Monitor.Enter(_internalLock, ref internalLockTaken);
                    Debug.Assert(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--;
                    Debug.Assert(_waitCount >= 0);
                    Monitor.Exit(_internalLock);
                }

                EnterLock(_externalLock, ref externalLockTaken);

                cancellationTokenRegistration.Dispose();
            }

            // Final check for predicate
            return(predicate(state));
        }
Ejemplo n.º 5
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.RegisterWithoutEC(token, _cancellationTokenCanceledEventHandler, this);
                }

                try { }
                finally
                {
                    Monitor.Enter(_internalLock, ref internalLockTaken);
                    Debug.Assert(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--;
                    Debug.Assert(_waitCount >= 0);
                    Monitor.Exit(_internalLock);
                }

                EnterLock(_externalLock, ref externalLockTaken);

                cancellationTokenRegistration.Dispose();
            }

            return(true);
        }
Ejemplo n.º 6
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.RegisterWithoutEC(token, _cancellationTokenCanceledEventHandler, this);
                }

                try { }
                finally
                {
                    Monitor.Enter(_lockObj, ref lockTaken);
                    Debug.Assert(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--;
                    Debug.Assert(_waitCount >= 0);
                    Monitor.Exit(_lockObj);
                }

                cancellationTokenRegistration.Dispose();
            }

            return(false);
        }
Ejemplo n.º 7
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.RegisterWithoutEC(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));
        }
Ejemplo n.º 8
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.RegisterWithoutEC(token, _cancellationTokenCanceledEventHandler, this));
 }
Ejemplo n.º 9
0
        /// <summary>
        /// Заблокироваться, если требуется
        /// </summary>
        /// <param name="timeout">Таймаут в миллисекундах</param>
        /// <param name="token">Токен отмены</param>
        /// <returns>Успешность (false - выход по таймауту)</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.RegisterWithoutEC(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);
        }