Ejemplo n.º 1
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>
        /// <returns>True if predicate evaluates to True</returns>
        /// <exception cref="ArgumentNullException">predicate is null</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<TState>(WaitPredicateRef<TState> predicate, ref TState state)
        {
            if (predicate == null)
                throw new ArgumentNullException(nameof(predicate));
            if (_sourceWaiter == null)
                throw new ObjectDisposedException(nameof(MonitorWaiter), "Lock section has exited");
            if (_sourceWaiter.IsDisposed)
                throw new ObjectDisposedException(nameof(MonitorObject), $"MonitorObject '{_sourceWaiter.Name}' was disposed");
            if (_token.IsCancellationRequested)
                throw new OperationCanceledException(_token);

            Debug.Assert(_sourceWaiter.IsEntered());

            if (predicate(ref state))
                return true;
            else if (_timeout == 0)
                return false;

            int remainingWaitMilliseconds = Timeout.Infinite;

            while (!_token.IsCancellationRequested && !_sourceWaiter.IsDisposed)
            {
                if (_timeout != Timeout.Infinite)
                {
                    remainingWaitMilliseconds = TimeoutHelper.UpdateTimeout(_startTime, _timeout);
                    if (remainingWaitMilliseconds <= 0)
                        break;
                }

                if (!Monitor.Wait(_sourceWaiter, remainingWaitMilliseconds))
                    break;

                if (predicate.Invoke(ref state))
                    return true;
            }


            // Check if cancellation or dispose was the reasons of the signal
            if (_token.IsCancellationRequested)
                throw new OperationCanceledException(_token);
            if (_sourceWaiter.IsDisposed)
                throw new OperationInterruptedException("Wait was interrupted by Dispose", new ObjectDisposedException(nameof(MonitorObject), $"MonitorObject '{_sourceWaiter.Name}' was disposed"));

            // Final check for predicate
            return predicate(ref state);
        }
Ejemplo n.º 2
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>
        /// <returns>True if predicate evaluates to True</returns>
        /// <exception cref="ArgumentNullException">predicate is null</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 <TState>(WaitPredicateRef <TState> predicate, ref TState state)
        {
            if (predicate == null)
            {
                throw new ArgumentNullException(nameof(predicate));
            }
            if (_sourceWaiter == null)
            {
                throw new ObjectDisposedException(nameof(ConditionVariableWaiter), "Lock section has exited");
            }
            if (_sourceWaiter.IsDisposed)
            {
                throw new ObjectDisposedException(nameof(ConditionVariable), $"ConditionVariable '{_sourceWaiter.Name}' was disposed");
            }
            if (_token.IsCancellationRequested)
            {
                throw new OperationCanceledException(_token);
            }

            TurboContract.Assert(_sourceWaiter.IsEntered(), conditionString: "_sourceWaiter.IsEntered()");

            if (predicate(ref state))
            {
                return(true);
            }
            else if (_timeout == 0)
            {
                return(false);
            }

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

            bool internalLockTaken = false;
            bool externalLockTaken = true;

            try
            {
                try { }
                finally
                {
                    Monitor.Enter(_sourceWaiter.InternalLock, ref internalLockTaken);
                    TurboContract.Assert(internalLockTaken, conditionString: "internalLockTaken");
                }

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

                // Check if cancellation or dispose was the reasons of the signal
                if (_token.IsCancellationRequested)
                {
                    throw new OperationCanceledException(_token);
                }
                if (_sourceWaiter.IsDisposed)
                {
                    throw new OperationInterruptedException("Wait was interrupted by Dispose", new ObjectDisposedException(nameof(ConditionVariable), $"ConditionVariable '{_sourceWaiter.Name}' was disposed"));
                }
            }
            finally
            {
                if (internalLockTaken)
                {
                    Monitor.Exit(_sourceWaiter.InternalLock);
                }

                EnterLock(_sourceWaiter.ExternalLock, ref externalLockTaken);
            }

            // Final check for predicate
            return(predicate(ref state));
        }
Ejemplo n.º 3
0
        private bool WaitUntilPredicate <TState>(ref bool internalLockTaken, ref bool externalLockTaken, WaitPredicateRef <TState> predicate, ref TState state)
        {
            TurboContract.Requires(internalLockTaken, "internalLockTaken == false");
            TurboContract.Requires(externalLockTaken, "externalLockTaken == false");
            TurboContract.Requires(predicate != null, conditionString: "predicate != null");

            int remainingWaitMilliseconds = Timeout.Infinite;

            while (true)
            {
                if (_token.IsCancellationRequested || _sourceWaiter.IsDisposed)
                {
                    return(false);
                }

                if (_timeout != Timeout.Infinite)
                {
                    remainingWaitMilliseconds = TimeoutHelper.UpdateTimeout(_startTime, _timeout);
                    if (remainingWaitMilliseconds <= 0)
                    {
                        return(false);
                    }
                }

                ExitLock(_sourceWaiter.ExternalLock, ref externalLockTaken);

                if (!Monitor.Wait(_sourceWaiter.InternalLock, remainingWaitMilliseconds))
                {
                    return(false);
                }

                try
                {
                    ExitLock(_sourceWaiter.InternalLock, ref internalLockTaken);
                    EnterLock(_sourceWaiter.ExternalLock, ref externalLockTaken);

                    if (predicate.Invoke(ref state))
                    {
                        return(true);
                    }
                }
                finally
                {
                    EnterLock(_sourceWaiter.InternalLock, ref internalLockTaken);
                }
            }
        }
Ejemplo n.º 4
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>
        /// <returns>True if predicate evaluates to True</returns>
        /// <exception cref="ArgumentNullException">predicate is null</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 <TState>(WaitPredicateRef <TState> predicate, ref TState state)
        {
            if (predicate == null)
            {
                throw new ArgumentNullException(nameof(predicate));
            }
            if (_sourceWaiter == null)
            {
                throw new ObjectDisposedException(nameof(ConditionVariableWaiter), "Lock section has exited");
            }
            if (_sourceWaiter.IsDisposed)
            {
                throw new ObjectDisposedException(nameof(ConditionVariable), $"ConditionVariable '{_sourceWaiter.Name}' was disposed");
            }
            if (_token.IsCancellationRequested)
            {
                throw new OperationCanceledException(_token);
            }

            Debug.Assert(_sourceWaiter.IsEntered());

            if (predicate(ref state))
            {
                return(true);
            }
            else if (_timeout == 0)
            {
                return(false);
            }

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

            int remainingWaitMilliseconds = Timeout.Infinite;

            var  waitingPrimitive = _sourceWaiter.RegisterWaiter();
            bool firstTry         = true;

            while (!_token.IsCancellationRequested && !_sourceWaiter.IsDisposed)
            {
                try
                {
                    if (waitingPrimitive.IsSet || firstTry)
                    {
                        firstTry = false;
                        waitingPrimitive.Reset();
                        _sourceWaiter.AddWaiterToQueue(waitingPrimitive);
                    }

                    Monitor.Exit(_sourceWaiter.ExternalLock);
                    if (Monitor.IsEntered(_sourceWaiter.ExternalLock))
                    {
                        throw new SynchronizationLockException("Recursive lock is not supported");
                    }

                    if (_timeout != Timeout.Infinite)
                    {
                        remainingWaitMilliseconds = TimeoutHelper.UpdateTimeout(_startTime, _timeout);
                        if (remainingWaitMilliseconds <= 0)
                        {
                            break;
                        }
                    }

                    if (!waitingPrimitive.Wait(remainingWaitMilliseconds))
                    {
                        break;
                    }
                }
                finally
                {
                    Monitor.Enter(_sourceWaiter.ExternalLock);
                    if (!waitingPrimitive.IsSet)
                    {
                        _sourceWaiter.RemoveWaiterFromQueue(waitingPrimitive);
                    }
                }

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

            // Check if cancellation or dispose was the reasons of the signal
            if (_token.IsCancellationRequested)
            {
                throw new OperationCanceledException(_token);
            }
            if (_sourceWaiter.IsDisposed)
            {
                throw new OperationInterruptedException("Wait was interrupted by Dispose", new ObjectDisposedException(nameof(ConditionVariableAlt), $"ConditionVariable '{_sourceWaiter.Name}' was disposed"));
            }


            // Final check for predicate
            return(predicate(ref state));
        }