/// <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); }
/// <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)); }
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); } } }
/// <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)); }