public void Lazy_EnsureSingleThreadSafeExecution() { counter = 42; var l = new Lazy <int>(delegate() { return(counter++); }, true); object monitor = new object(); var threads = new Thread[10]; for (int i = 0; i < 10; ++i) { threads[i] = new Thread(delegate() { lock (monitor) { Monitor.Wait(monitor); } int val = l.Value; }); } for (int i = 0; i < 10; ++i) { threads[i].Start(); } lock (monitor) Monitor.PulseAll(monitor); Assert.AreEqual(42, l.Value); }
public void Monitor_TryEnter_Invalid() { bool lockTaken = false; var obj = new object(); AssertExtensions.Throws <ArgumentNullException>("obj", () => Monitor.TryEnter(null)); AssertExtensions.Throws <ArgumentNullException>("obj", () => Monitor.TryEnter(null, ref lockTaken)); AssertExtensions.Throws <ArgumentNullException>("obj", () => Monitor.TryEnter(null, 1)); AssertExtensions.Throws <ArgumentNullException>("obj", () => Monitor.TryEnter(null, 1, ref lockTaken)); AssertExtensions.Throws <ArgumentNullException>("obj", () => Monitor.TryEnter(null, TimeSpan.Zero)); AssertExtensions.Throws <ArgumentNullException>("obj", () => Monitor.TryEnter(null, TimeSpan.Zero, ref lockTaken)); //AssertExtensions.Throws<ArgumentOutOfRangeException>("millisecondsTimeout", () => Monitor.TryEnter(null, -1)); //AssertExtensions.Throws<ArgumentOutOfRangeException>("millisecondsTimeout", () => Monitor.TryEnter(null, -1, ref lockTaken)); //AssertExtensions.Throws<ArgumentOutOfRangeException>("timeout", () => Monitor.TryEnter(null, TimeSpan.FromMilliseconds(-1))); //AssertExtensions.Throws<ArgumentOutOfRangeException>("timeout", () => Monitor.TryEnter(null, TimeSpan.FromMilliseconds(-1), ref lockTaken)); AssertExtensions.Throws <ArgumentNullException>("obj", () => Monitor.TryEnter(null, -1)); AssertExtensions.Throws <ArgumentNullException>("obj", () => Monitor.TryEnter(null, -1, ref lockTaken)); AssertExtensions.Throws <ArgumentNullException>("obj", () => Monitor.TryEnter(null, TimeSpan.FromMilliseconds(-1))); AssertExtensions.Throws <ArgumentNullException>("obj", () => Monitor.TryEnter(null, TimeSpan.FromMilliseconds(-1), ref lockTaken)); lockTaken = true; AssertExtensions.Throws <ArgumentException>("lockTaken", () => Monitor.TryEnter(obj, ref lockTaken)); lockTaken = true; AssertExtensions.Throws <ArgumentException>("lockTaken", () => Monitor.TryEnter(obj, 0, ref lockTaken)); lockTaken = true; AssertExtensions.Throws <ArgumentException>("lockTaken", () => Monitor.TryEnter(obj, TimeSpan.Zero, ref lockTaken)); }
private static void CancellationTokenCallback(object obj) { ManualResetEventSlim mre = obj as ManualResetEventSlim; Debug.Assert(mre != null, "Expected a ManualResetEventSlim"); Debug.Assert(mre.m_lock != null); //the lock should have been created before this callback is registered for use. lock (mre.m_lock) { Monitor2.PulseAll(mre.m_lock); // awaken all waiters } }
public void Monitor_Enter_SetsLockTaken() { bool lockTaken = false; var obj = new object(); Monitor.Enter(obj, ref lockTaken); Assert.IsTrue(lockTaken); Monitor.Exit(obj); // The documentation does not specifies that lockTaken variable is // set to false after Exit is called // Assert.IsFalse(lockTaken); }
public void Monitor_Wait_Invalid() { var obj = new object(); AssertExtensions.Throws <ArgumentNullException>("obj", () => Monitor.Wait(null)); AssertExtensions.Throws <ArgumentNullException>("obj", () => Monitor.Wait(null, 1)); AssertExtensions.Throws <ArgumentNullException>("obj", () => Monitor.Wait(null, TimeSpan.Zero)); //AssertExtensions.Throws<ArgumentOutOfRangeException>("millisecondsTimeout", () => Monitor.Wait(null, -1)); //AssertExtensions.Throws<ArgumentOutOfRangeException>("timeout", () => Monitor.Wait(null, TimeSpan.FromMilliseconds(-1))); AssertExtensions.Throws <ArgumentNullException>("obj", () => Monitor.Wait(null, -1)); AssertExtensions.Throws <ArgumentNullException>("obj", () => Monitor.Wait(null, TimeSpan.FromMilliseconds(-1))); }
public void Monitor_Enter_Invalid() { bool lockTaken = false; var obj = new object(); AssertExtensions.Throws <ArgumentNullException>("obj", () => Monitor.Enter(null)); AssertExtensions.Throws <ArgumentNullException>("obj", () => Monitor.Enter(null, ref lockTaken)); Assert.IsFalse(lockTaken); lockTaken = true; AssertExtensions.Throws <ArgumentException>("lockTaken", () => Monitor.Enter(obj, ref lockTaken)); //Assert.IsFalse(lockTaken); Assert.IsTrue(lockTaken); }
/// <summary> /// Private helper to actually perform the Set. /// </summary> /// <param name="duringCancellation">Indicates whether we are calling Set() during cancellation.</param> /// <exception cref="T:System.OperationCanceledException">The object has been canceled.</exception> private void Set(bool duringCancellation) { // We need to ensure that IsSet=true does not get reordered past the read of m_eventObj // This would be a legal movement according to the .NET memory model. // The code is safe as IsSet involves an Interlocked.CompareExchange which provides a full memory barrier. IsSet = true; // If there are waiting threads, we need to pulse them. if (Waiters > 0) { Debug.Assert(m_lock != null); //if waiters>0, then m_lock has already been created. lock (m_lock) { Monitor2.PulseAll(m_lock); } } ManualResetEvent eventObj = m_eventObj; //Design-decision: do not set the event if we are in cancellation -> better to deadlock than to wake up waiters incorrectly //It would be preferable to wake up the event and have it throw OCE. This requires MRE to implement cancellation logic if (eventObj != null && !duringCancellation) { // We must surround this call to Set in a lock. The reason is fairly subtle. // Sometimes a thread will issue a Wait and wake up after we have set m_state, // but before we have gotten around to setting m_eventObj (just below). That's // because Wait first checks m_state and will only access the event if absolutely // necessary. However, the coding pattern { event.Wait(); event.Dispose() } is // quite common, and we must support it. If the waiter woke up and disposed of // the event object before the setter has finished, however, we would try to set a // now-disposed Win32 event. Crash! To deal with this race condition, we use a lock to // protect access to the event object when setting and disposing of it. We also // double-check that the event has not become null in the meantime when in the lock. lock (eventObj) { if (m_eventObj != null) { // If somebody is waiting, we must set the event. m_eventObj.Set(); } } } #if DEBUG m_lastSetTime = DateTime.UtcNow.Ticks; #endif }
public void Monitor_BasicRecursion() { var obj = new object(); Assert.IsTrue(Monitor.TryEnter(obj)); Assert.IsTrue(Monitor.TryEnter(obj)); Monitor.Exit(obj); //Assert.IsTrue(Monitor.IsEntered(obj)); Monitor.Enter(obj); //Assert.IsTrue(Monitor.IsEntered(obj)); Monitor.Exit(obj); //Assert.IsTrue(Monitor.IsEntered(obj)); Monitor.Exit(obj); //Assert.IsFalse(Monitor.IsEntered(obj)); }
public void Monitor_Exit_Invalid() { var obj = new object(); int valueType = 1; AssertExtensions.Throws <ArgumentNullException>("obj", () => Monitor.Exit(null)); #if !WindowsCE AssertExtensions.Throws <SynchronizationLockException>(() => Monitor.Exit(obj)); AssertExtensions.Throws <SynchronizationLockException>(() => Monitor.Exit(new object())); AssertExtensions.Throws <SynchronizationLockException>(() => Monitor.Exit(valueType)); #else AssertExtensions.Throws <ArgumentException>(() => Monitor.Exit(obj)); AssertExtensions.Throws <ArgumentException>(() => Monitor.Exit(new object())); AssertExtensions.Throws <ArgumentException>(() => Monitor.Exit(valueType)); #endif }
public void Monitor_DeepRecursion() { var obj = new object(); var hc = obj.GetHashCode(); // reduced from "(long)int.MaxValue + 2;" to something that will return in a more meaningful time const int limit = 10000; for (var i = 0L; i < limit; i++) { Assert.IsTrue(Monitor.TryEnter(obj)); } for (var j = 0L; j < (limit - 1); j++) { Monitor.Exit(obj); //Assert.IsTrue(Monitor.IsEntered(obj)); } Monitor.Exit(obj); //Assert.IsTrue(Monitor.IsEntered(obj)); }
public void Monitor_WaitTest() { var obj = new object(); var waitTests = new Func <bool>[] { () => Monitor.Wait(obj, FailTimeoutMilliseconds), () => Monitor.Wait(obj, FailTimeoutMilliseconds), () => Monitor.Wait(obj, TimeSpan.FromMilliseconds(FailTimeoutMilliseconds)), () => Monitor.Wait(obj, TimeSpan.FromMilliseconds(FailTimeoutMilliseconds)), }; var t = new Thread(() => { Monitor.Enter(obj); for (int i = 0; i < waitTests.Length; ++i) { Monitor.Pulse(obj); Monitor.Wait(obj, FailTimeoutMilliseconds); } Monitor.Exit(obj); }); t.IsBackground = true; Monitor.Enter(obj); t.Start(); int counter = 0; foreach (var waitTest in waitTests) { Assert.IsTrue(waitTest(), "#" + counter.ToString()); Monitor.Pulse(obj); counter++; } Monitor.Exit(obj); }
/// <summary> /// Default Constructor /// </summary> public EventQueuePC() { queue = new Queue<Event>(); itemCount = 0; monitor = new Monitor2(); }
/// <summary> /// Blocks the current thread until it can enter the <see cref="SemaphoreSlim"/>, /// using a 32-bit signed integer to measure the time interval, /// while observing a <see cref="T:System.Threading.CancellationToken"/>. /// </summary> /// <param name="millisecondsTimeout">The number of milliseconds to wait, or <see cref="Timeout.Infinite"/>(-1) to /// wait indefinitely.</param> /// <param name="cancellationToken">The <see cref="T:System.Threading.CancellationToken"/> to observe.</param> /// <returns>true if the current thread successfully entered the <see cref="SemaphoreSlim"/>; otherwise, false.</returns> /// <exception cref="ArgumentOutOfRangeException"><paramref name="millisecondsTimeout"/> is a negative number other than -1, /// which represents an infinite time-out.</exception> /// <exception cref="System.OperationCanceledException"><paramref name="cancellationToken"/> was canceled.</exception> public bool Wait(int millisecondsTimeout, CancellationToken cancellationToken) { CheckDispose(); // Validate input if (millisecondsTimeout < -1) { throw new ArgumentOutOfRangeException( "totalMilliSeconds", millisecondsTimeout, GetResourceString("SemaphoreSlim_Wait_TimeoutWrong")); } cancellationToken.ThrowIfCancellationRequested(); long startTimeTicks = 0; if (millisecondsTimeout != Timeout.Infinite && millisecondsTimeout > 0) { startTimeTicks = DateTime.UtcNow.Ticks; } bool lockTaken = false; //Register for cancellation outside of the main lock. //NOTE: Register/deregister inside the lock can deadlock as different lock acquisition orders could // occur for (1)this.m_lockObj and (2)cts.internalLock CancellationTokenRegistration cancellationTokenRegistration = cancellationToken.Register(s_cancellationTokenCanceledEventHandler, this); try { // Perf: first spin wait for the count to be positive, but only up to the first planned yield. // This additional amount of spinwaiting in addition // to Monitor2.Enter()’s spinwaiting has shown measurable perf gains in test scenarios. // SpinWait spin = new SpinWait(); while (m_currentCount == 0 && !spin.NextSpinWillYield) { spin.SpinOnce(); } // entering the lock and incrementing waiters must not suffer a thread-abort, else we cannot // clean up m_waitCount correctly, which may lead to deadlock due to non-woken waiters. try { } finally { Monitor2.Enter(m_lockObj, ref lockTaken); if (lockTaken) { m_waitCount++; } } // If the count > 0 we are good to move on. // If not, then wait if we were given allowed some wait duration if (m_currentCount == 0) { if (millisecondsTimeout == 0) { return(false); } // Prepare for the main wait... // wait until the count become greater than zero or the timeout is expired if (!WaitUntilCountOrTimeout(millisecondsTimeout, startTimeTicks, cancellationToken)) { return(false); } } // At this point the count should be greater than zero Contract.Assert(m_currentCount > 0); m_currentCount--; // Exposing wait handle which is lazily initialized if needed if (m_waitHandle != null && m_currentCount == 0) { m_waitHandle.Reset(); } } finally { // Release the lock if (lockTaken) { m_waitCount--; Monitor.Exit(m_lockObj); } // Unregister the cancellation callback. cancellationTokenRegistration.Dispose(); } return(true); }
/// <summary> /// Blocks the current thread until the current <see cref="ManualResetEventSlim"/> is set, using a /// 32-bit signed integer to measure the time interval, while observing a <see /// cref="T:System.Threading.CancellationToken"/>. /// </summary> /// <param name="millisecondsTimeout">The number of milliseconds to wait, or <see /// cref="Timeout.Infinite"/>(-1) to wait indefinitely.</param> /// <param name="cancellationToken">The <see cref="T:System.Threading.CancellationToken"/> to /// observe.</param> /// <returns>true if the <see cref="System.Threading.ManualResetEventSlim"/> was set; otherwise, /// false.</returns> /// <exception cref="T:System.ArgumentOutOfRangeException"><paramref name="millisecondsTimeout"/> is a /// negative number other than -1, which represents an infinite time-out.</exception> /// <exception cref="T:System.InvalidOperationException"> /// The maximum number of waiters has been exceeded. /// </exception> /// <exception cref="T:System.Threading.OperationCanceledException"><paramref /// name="cancellationToken"/> was canceled.</exception> public bool Wait(int millisecondsTimeout, CancellationToken cancellationToken) { ThrowIfDisposed(); cancellationToken.ThrowIfCancellationRequested(); // an early convenience check if (millisecondsTimeout < -1) { throw new ArgumentOutOfRangeException(nameof(millisecondsTimeout)); } if (!IsSet) { if (millisecondsTimeout == 0) { // For 0-timeouts, we just return immediately. return(false); } // We spin briefly before falling back to allocating and/or waiting on a true event. uint startTime = 0; bool bNeedTimeoutAdjustment = false; int realMillisecondsTimeout = millisecondsTimeout; //this will be adjusted if necessary. if (millisecondsTimeout != Timeout.Infinite) { // We will account for time spent spinning, so that we can decrement it from our // timeout. In most cases the time spent in this section will be negligible. But // we can't discount the possibility of our thread being switched out for a lengthy // period of time. The timeout adjustments only take effect when and if we actually // decide to block in the kernel below. //startTime = TimeoutHelper.GetTime(); startTime = (uint)Environment.TickCount; bNeedTimeoutAdjustment = true; } // Spin int spinCount = SpinCount; var spinner = new SpinWait(); while (spinner.Count < spinCount) { spinner.SpinOnce(SpinWait.Sleep1ThresholdForSpinBeforeWait); if (IsSet) { return(true); } if (spinner.Count >= 100 && spinner.Count % 10 == 0) // check the cancellation token if the user passed a very large spin count { cancellationToken.ThrowIfCancellationRequested(); } } // Now enter the lock and wait. EnsureLockObjectCreated(); // We must register and deregister the token outside of the lock, to avoid deadlocks. //using (cancellationToken.InternalRegisterWithoutEC(s_cancellationTokenCallback, this)) using (cancellationToken.Register(s_cancellationTokenCallback, this)) { lock (m_lock) { // Loop to cope with spurious wakeups from other waits being canceled while (!IsSet) { // If our token was canceled, we must throw and exit. cancellationToken.ThrowIfCancellationRequested(); //update timeout (delays in wait commencement are due to spinning and/or spurious wakeups from other waits being canceled) if (bNeedTimeoutAdjustment) { realMillisecondsTimeout = TimeoutHelper.UpdateTimeOut(startTime, millisecondsTimeout); if (realMillisecondsTimeout <= 0) { return(false); } } // There is a race condition that Set will fail to see that there are waiters as Set does not take the lock, // so after updating waiters, we must check IsSet again. // Also, we must ensure there cannot be any reordering of the assignment to Waiters and the // read from IsSet. This is guaranteed as Waiters{set;} involves an Interlocked.CompareExchange // operation which provides a full memory barrier. // If we see IsSet=false, then we are guaranteed that Set() will see that we are // waiting and will pulse the monitor correctly. Waiters = Waiters + 1; if (IsSet) //This check must occur after updating Waiters. { Waiters--; //revert the increment. return(true); } // Now finally perform the wait. try { // ** the actual wait ** if (!Monitor2.Wait(m_lock, realMillisecondsTimeout)) { return(false); //return immediately if the timeout has expired. } } finally { // Clean up: we're done waiting. Waiters = Waiters - 1; } // Now just loop back around, and the right thing will happen. Either: // 1. We had a spurious wake-up due to some other wait being canceled via a different cancellationToken (rewait) // or 2. the wait was successful. (the loop will break) } } } } // automatically disposes (and deregisters) the callback return(true); //done. The wait was satisfied. }
public bool Wait(int millisecondsTimeout) { if (millisecondsTimeout < -1) { throw new ArgumentOutOfRangeException(nameof(millisecondsTimeout), SR.ArgumentOutOfRange_NeedNonNegOrNegative1); } //if (!_lock.IsAcquired) // throw new SynchronizationLockException(); Waiter waiter = GetWaiterForCurrentThread(); AddWaiter(waiter); //uint recursionCount = _lock.ReleaseAll(); var lockObject = _lockWeakObject.Target; if (!_lockWeakObject.IsAlive) { throw new SynchronizationLockException(SynchronizationObjectDisposed); } uint recursionCount = Monitor2.ReleaseAll(lockObject); bool success = false; try { // Since that IsAcquired is not available ensure that // the lock was freed if (recursionCount == 0) { throw new SynchronizationLockException(); } success = waiter.ev.WaitOne(millisecondsTimeout); } finally { //_lock.Reacquire(recursionCount); //Debug.Assert(_lock.IsAcquired); Monitor2.Reacquire(lockObject, recursionCount); if (!waiter.signalled) { RemoveWaiter(waiter); } else if (!success) { // // The wait timed out, but we were signalled before we could reacquire the lock. // Since WaitOne timed out, it didn't trigger the auto-reset of the AutoResetEvent. // So, we need to manually reset the event. // waiter.ev.Reset(); } AssertIsNotInList(waiter); } return(waiter.signalled); }
public void Monitor_PulseAll_Invalid() { var obj = new object(); AssertExtensions.Throws <ArgumentNullException>("obj", () => Monitor.PulseAll(null)); }
/// <summary> /// Constructor vacío /// </summary> public NetMessageQueue() { queue = new Queue<NetMessage>(); itemCount = 0; monitor = new Monitor2(); }
/// <summary> /// Default Constructor /// </summary> public MessageMonitoredQueue() { queue = new Queue<Message>(); itemCount = 0; monitor = new Monitor2(); }