示例#1
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);
        }
示例#2
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);
        }
示例#3
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));
        }
示例#4
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);
        }
示例#5
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);
        }