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);
        }
Beispiel #2
0
        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));
        }
Beispiel #3
0
        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
            }
        }
Beispiel #4
0
        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);
        }
Beispiel #5
0
        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)));
        }
Beispiel #6
0
        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);
        }
Beispiel #7
0
        /// <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
        }
Beispiel #8
0
        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));
        }
Beispiel #9
0
        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
        }
Beispiel #10
0
        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));
        }
Beispiel #11
0
        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();
 }
Beispiel #13
0
        /// <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);
        }
Beispiel #14
0
        /// <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.
        }
Beispiel #15
0
        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);
        }
Beispiel #16
0
        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();
 }