Пример #1
0
        public void TestProducerConsumer()
        {
            const int      NumIters = 500;
            SemaphoreLight inst     = new SemaphoreLight(0);

            var task1 = Task.Factory.StartNew(() =>
            {
                for (int i = 0; i < NumIters; i++)
                {
                    Assert.IsTrue(inst.Wait(30000));
                }
                Assert.IsFalse(inst.Wait(0));
            }, TaskCreationOptions.LongRunning);

            var task2 = Task.Factory.StartNew(() =>
            {
                for (int i = 0; i < NumIters; i++)
                {
                    inst.Release();
                }
            }, TaskCreationOptions.LongRunning);


            Task.WaitAll(task1, task2);
        }
        public void WaitTest()
        {
            const int sleepTime    = 200;
            const int initialCount = 2;
            var       target       = new SemaphoreLight(initialCount);

            var start = DateTime.Now;

            target.Wait();
            target.Wait();

            Assert.IsTrue((DateTime.Now - start).TotalMilliseconds < 50);

            var releaseThread = new Thread(
                () =>
            {
                Thread.Sleep(sleepTime);
                target.Release();
            });

            releaseThread.Start();

            target.Wait();

            var end     = DateTime.Now;
            var elapsed = end - start;

            Assert.IsTrue(elapsed.TotalMilliseconds > 200);
            Assert.IsTrue(elapsed.TotalMilliseconds < 250);
        }
Пример #3
0
            public T GetObject()
            {
                if (!_sem.Wait(0, new CancellationToken()))
                {
                    _sem.Wait();
                }
                T item;

                _objects.TryPop(out item);
                return(item);
                //return _objects.TryTake();
                //return _objects.Take();
            }
Пример #4
0
        public void TestTimeoutWork()
        {
            SemaphoreLight inst = new SemaphoreLight(0);

            Assert.IsFalse(inst.Wait(1000));
            Assert.AreEqual(0, inst.CurrentCount);
        }
Пример #5
0
        public void TestCancellation()
        {
            SemaphoreLight          inst     = new SemaphoreLight(0);
            CancellationTokenSource tokenSrc = new CancellationTokenSource();
            bool cancelled = false;

            Task.Run(() =>
            {
                try
                {
                    inst.Wait(tokenSrc.Token);
                }
                catch (OperationCanceledException)
                {
                    Volatile.Write(ref cancelled, true);
                    Thread.MemoryBarrier();
                }
            });

            TimingAssert.IsTrue(5000, () => inst.WaiterCount > 0);
            Assert.IsFalse(Volatile.Read(ref cancelled));

            tokenSrc.Cancel();
            TimingAssert.IsTrue(5000, () => Volatile.Read(ref cancelled));

            Assert.AreEqual(0, inst.CurrentCount);
            Assert.AreEqual(0, inst.WaiterCount);
        }
Пример #6
0
        public void WaitTest()
        {
            int            initialCount = 0;                                // TODO: Initialize to an appropriate value
            SemaphoreLight target       = new SemaphoreLight(initialCount); // TODO: Initialize to an appropriate value

            target.Wait();
            Assert.Inconclusive("A method that does not return a value cannot be verified.");
        }
        /// <summary>
        /// Выбрать элемент из списка свободных
        /// </summary>
        /// <param name="element">Выбранный элемент</param>
        /// <param name="timeout">Таймаут</param>
        /// <param name="token">Токен отмены</param>
        /// <returns>Успешность</returns>
        private bool TryTakeInner(out PoolElementWrapper <T> element, int timeout, CancellationToken token)
        {
            element = null;

            if (token.IsCancellationRequested)
            {
                throw new OperationCanceledException(token);
            }


            bool waitForSemaphoreWasSuccessful = _occupiedElements.Wait(0);

            if (waitForSemaphoreWasSuccessful == false && timeout != 0)
            {
                waitForSemaphoreWasSuccessful = _occupiedElements.Wait(timeout, token);
            }

            if (!waitForSemaphoreWasSuccessful)
            {
                return(false);
            }

            bool removeSucceeded = false;
            bool removeFaulted   = true;

            try
            {
                //token.ThrowIfCancellationRequested(); // TODO: Refactor the code
                removeSucceeded = this.TryTakeCore(out element);
                TurboContract.Assert(removeSucceeded, "Take from underlying collection return false");
                removeFaulted = false;
            }
            finally
            {
                if (!removeSucceeded && removeFaulted)
                {
                    _occupiedElements.Release();
                }
            }

            return(removeSucceeded);
        }
Пример #8
0
        public void TestReleaseWait()
        {
            SemaphoreLight inst = new SemaphoreLight(0);

            Assert.AreEqual(0, inst.CurrentCount);

            inst.Release();
            Assert.AreEqual(1, inst.CurrentCount);

            Assert.IsTrue(inst.Wait(0));
            Assert.AreEqual(0, inst.CurrentCount);
        }
        public bool TryAdd(ThreadPoolWorkItem item, int timeout)
        {
            Contract.Requires(item != null);

            bool freeNodesExist = true;

            if (_freeNodes != null)
            {
                freeNodesExist = _freeNodes.Wait(0);
                if (freeNodesExist == false && timeout != 0)
                {
                    freeNodesExist = _freeNodes.Wait(timeout);
                }
            }

            if (freeNodesExist)
            {
                _mainQueue.Add(item);
                _occupiedNodes.Release();
                return(true);
            }

            return(false);
        }
Пример #10
0
        public void TestManyReleaseWait()
        {
            SemaphoreLight inst = new SemaphoreLight(0);

            for (int i = 0; i < 100; i++)
            {
                Assert.AreEqual(i, inst.CurrentCount);
                inst.Release();
            }

            for (int i = 100; i > 0; i--)
            {
                Assert.AreEqual(i, inst.CurrentCount);
                Assert.IsTrue(inst.Wait(10));
            }

            Assert.AreEqual(0, inst.CurrentCount);
        }
Пример #11
0
        public void TestWakeUpOnRelease()
        {
            SemaphoreLight inst   = new SemaphoreLight(0);
            bool           wakeUp = false;

            Task.Run(() =>
            {
                inst.Wait();
                wakeUp = true;
            });

            TimingAssert.IsTrue(5000, () => inst.WaiterCount > 0);
            Assert.IsFalse(wakeUp);

            inst.Release();
            TimingAssert.IsTrue(5000, () => Volatile.Read(ref wakeUp));

            Assert.AreEqual(0, inst.CurrentCount);
            Assert.AreEqual(0, inst.WaiterCount);
        }
Пример #12
0
        /// <summary>
        /// Removes completed batch from the head of the queue (inner core method)
        /// </summary>
        /// <param name="batch">The batch removed from queue</param>
        /// <param name="timeout">Removing timeout</param>
        /// <param name="token">Cancellation token</param>
        /// <returns>True if the batch was removed</returns>
        /// <exception cref="OperationCanceledException">Cancellation was requested by token</exception>
        /// <exception cref="ObjectDisposedException">Queue was disposed</exception>
        private bool TryTakeInner(out T[] batch, int timeout, CancellationToken token)
        {
            if (_isDisposed)
            {
                throw new ObjectDisposedException(this.GetType().Name);
            }
            if (token.IsCancellationRequested)
            {
                throw new OperationCanceledException(token);
            }

            batch = null;

            bool batchTaken = false;
            bool entered    = false;

            try
            {
                if (_occupiedBatches.Wait(timeout, token))
                {
                    entered = true;

                    batchTaken = _innerQueue.TryDequeue(out batch);
                    Debug.Assert(batchTaken == true, "Collection is inconsistent");
                }
            }
            finally
            {
                if (!batchTaken && entered)
                {
                    _occupiedBatches.Release();
                }
                if (batchTaken && _freeNodes != null)
                {
                    _freeNodes.Release(batch.Length);
                }
            }

            return(batchTaken);
        }
Пример #13
0
        /// <summary>
        /// Adds new item to the tail of the queue (inner core method)
        /// </summary>
        /// <param name="item">New item</param>
        /// <param name="timeout">Adding timeout</param>
        /// <param name="token">Cancellation token</param>
        /// <returns>Was added sucessufully</returns>
        /// <exception cref="OperationCanceledException">Cancellation was requested by token</exception>
        /// <exception cref="ObjectDisposedException">Queue was disposed</exception>
        private bool TryAddInner(T item, int timeout, CancellationToken token)
        {
            if (_isDisposed)
            {
                throw new ObjectDisposedException(this.GetType().Name);
            }
            if (token.IsCancellationRequested)
            {
                throw new OperationCanceledException(token);
            }

            bool elementAdded        = false;
            int  batchCountIncreased = 0;
            bool entered             = false;

            try
            {
                if (_freeNodes == null || _freeNodes.Wait(timeout, token))
                {
                    entered = true;
                    _innerQueue.Enqueue(item, out batchCountIncreased);
                    elementAdded = true;
                }
            }
            finally
            {
                if (!elementAdded && entered && _freeNodes != null)
                {
                    _freeNodes.Release();
                }
                if (elementAdded && batchCountIncreased > 0)
                {
                    _occupiedBatches.Release(batchCountIncreased);
                }
            }

            return(elementAdded);
        }
Пример #14
0
        public void OverflowTest()
        {
            SemaphoreLight inst = new SemaphoreLight(0);

            inst.Release(int.MaxValue - 100);
            Assert.AreEqual(int.MaxValue - 100, inst.CurrentCount);

            inst.Release(100);
            Assert.AreEqual(int.MaxValue, inst.CurrentCount);

            try
            {
                inst.Release();
                Assert.Fail("SemaphoreFullException expected");
            }
            catch (SemaphoreFullException)
            {
            }

            bool waitResult = inst.Wait(0);

            Assert.IsTrue(waitResult);
        }
Пример #15
0
        private void RunComplexTest(SemaphoreLight sem, int elemCount, int thCount)
        {
            int atomicRandom = 0;

            int trackElemCount   = elemCount;
            int waitedTimesCount = 0;
            int addFinished      = 0;

            Thread[] threadsTake = new Thread[thCount];
            Thread[] threadsAdd  = new Thread[thCount];

            CancellationTokenSource tokSrc = new CancellationTokenSource();

            Action addAction = () =>
            {
                Random rnd = new Random(Environment.TickCount + Interlocked.Increment(ref atomicRandom) * thCount * 2);

                while (true)
                {
                    int item = Interlocked.Decrement(ref trackElemCount);
                    if (item < 0)
                    {
                        break;
                    }

                    sem.Release();

                    int sleepTime = rnd.Next(100);
                    if (sleepTime > 0)
                    {
                        Thread.SpinWait(sleepTime);
                    }
                }

                Interlocked.Increment(ref addFinished);
            };


            Action takeAction = () =>
            {
                Random rnd = new Random(Environment.TickCount + Interlocked.Increment(ref atomicRandom) * thCount * 2);

                try
                {
                    while (Volatile.Read(ref addFinished) < thCount)
                    {
                        sem.Wait(tokSrc.Token);
                        Interlocked.Increment(ref waitedTimesCount);

                        int sleepTime = rnd.Next(100);
                        if (sleepTime > 0)
                        {
                            Thread.SpinWait(sleepTime);
                        }
                    }
                }
                catch (OperationCanceledException) { }

                TestContext.WriteLine("One take thread exit main cycle");

                while (sem.Wait(0))
                {
                    Interlocked.Increment(ref waitedTimesCount);
                }
            };


            for (int i = 0; i < threadsTake.Length; i++)
            {
                threadsTake[i] = new Thread(new ThreadStart(takeAction));
            }
            for (int i = 0; i < threadsAdd.Length; i++)
            {
                threadsAdd[i] = new Thread(new ThreadStart(addAction));
            }


            for (int i = 0; i < threadsTake.Length; i++)
            {
                threadsTake[i].Start();
            }
            for (int i = 0; i < threadsAdd.Length; i++)
            {
                threadsAdd[i].Start();
            }

            TestContext.WriteLine("All threads started");

            for (int i = 0; i < threadsAdd.Length; i++)
            {
                threadsAdd[i].Join();
            }

            TestContext.WriteLine("All add threads stopped");

            tokSrc.Cancel();

            TestContext.WriteLine("Cancell called");

            for (int i = 0; i < threadsTake.Length; i++)
            {
                threadsTake[i].Join();
            }

            TestContext.WriteLine("All take threads stopped");


            Assert.AreEqual(elemCount, waitedTimesCount);
        }
        /// <summary>
        /// Попытаться получить элемент из главной очереди
        /// </summary>
        /// <param name="item">Полученный элемент</param>
        /// <param name="timeout">Таймаут</param>
        /// <param name="token">Токен отмены</param>
        /// <param name="throwOnCancellation">Выбрасывать ли исключение при отмене по токену</param>
        /// <returns>Удалось ли получить</returns>
        public bool TryTake(out ThreadPoolWorkItem item, int timeout, CancellationToken token, bool throwOnCancellation)
        {
            Contract.Ensures(Contract.Result <bool>() == false || Contract.ValueAtReturn(out item) != null);

            item = null;

            if (token.IsCancellationRequested)
            {
                if (throwOnCancellation)
                {
                    throw new OperationCanceledException(token);
                }

                return(false);
            }

            bool occupiedNodesExist = _occupiedNodes.Wait(0);

            if (occupiedNodesExist == false && timeout != 0)
            {
                occupiedNodesExist = _occupiedNodes.Wait(timeout, token, throwOnCancellation);
            }

            if (occupiedNodesExist)
            {
                bool wasElementTaken = false;
                bool takePerformed   = true;
                try
                {
                    if (token.IsCancellationRequested)
                    {
                        if (throwOnCancellation)
                        {
                            throw new OperationCanceledException(token);
                        }

                        return(false);
                    }
                    wasElementTaken = _mainQueue.TryTake(out item);
                    takePerformed   = false;
                    Debug.Assert(wasElementTaken, "Incorrect collection state. Can't take items from collection when they should be there");
                }
                finally
                {
                    if (wasElementTaken)
                    {
                        if (_freeNodes != null)
                        {
                            // Не освобождаем, если запрошен экстеншн
                            if (Volatile.Read(ref _extendedCapacityRequest) <= 0 || Interlocked.Decrement(ref _extendedCapacityRequest) < 0)
                            {
                                _freeNodes.Release();
                            }
                        }
                    }
                    else
                    {
                        if (takePerformed)
                        {
                            _occupiedNodes.Release();
                        }
                    }
                }
            }
            return(occupiedNodesExist);
        }
Пример #17
0
        private static TimeSpan TestSemaphoreLight(string name, int elemCount, int addThCount, int takeThCount, int addSpin, int takeSpin)
        {
            SemaphoreLight sem = new SemaphoreLight(0, int.MaxValue);

            CancellationTokenSource srcCancel = new CancellationTokenSource();

            Thread[] addThreads  = new Thread[addThCount];
            Thread[] takeThreads = new Thread[takeThCount];

            int addedElemCount = 0;

            Barrier barierStart  = new Barrier(1 + addThreads.Length + takeThreads.Length);
            Barrier barierAdders = new Barrier(1 + addThreads.Length);
            Barrier barierTakers = new Barrier(1 + takeThreads.Length);

            Action addAction = () =>
            {
                barierStart.SignalAndWait();

                int index = 0;
                while ((index = Interlocked.Increment(ref addedElemCount)) <= elemCount)
                {
                    sem.Release();
                    SpinWaitHelper.SpinWait(addSpin);
                }

                barierAdders.SignalAndWait();
            };


            Action takeAction = () =>
            {
                CancellationToken myToken = srcCancel.Token;

                barierStart.SignalAndWait();

                try
                {
                    while (!srcCancel.IsCancellationRequested)
                    {
                        sem.Wait(myToken);
                        SpinWaitHelper.SpinWait(takeSpin);
                    }
                }
                catch (OperationCanceledException)
                {
                }

                while (sem.Wait(0))
                {
                }

                barierTakers.SignalAndWait();
            };

            for (int i = 0; i < addThreads.Length; i++)
            {
                addThreads[i] = new Thread(new ThreadStart(addAction));
            }
            for (int i = 0; i < takeThreads.Length; i++)
            {
                takeThreads[i] = new Thread(new ThreadStart(takeAction));
            }


            for (int i = 0; i < takeThreads.Length; i++)
            {
                takeThreads[i].Start();
            }
            for (int i = 0; i < addThreads.Length; i++)
            {
                addThreads[i].Start();
            }

            barierStart.SignalAndWait();

            Stopwatch sw = Stopwatch.StartNew();

            barierAdders.SignalAndWait();
            srcCancel.Cancel();
            barierTakers.SignalAndWait();
            sw.Stop();

            for (int i = 0; i < addThreads.Length; i++)
            {
                addThreads[i].Join();
            }
            for (int i = 0; i < takeThreads.Length; i++)
            {
                takeThreads[i].Join();
            }

            Console.WriteLine(name + ". SemaphoreLight. Time = " + sw.ElapsedMilliseconds.ToString() + "ms");
            return(sw.Elapsed);
        }