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