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); }
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 } }
/// <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_PulseAll_Invalid() { var obj = new object(); AssertExtensions.Throws <ArgumentNullException>("obj", () => Monitor.PulseAll(null)); }