SpinOnce() 공개 메소드

public SpinOnce ( ) : void
리턴 void
        public void MeasureThroughput()
        {
            const int sendMessageCount = 2000000;

            var senderTransport = CreateAndStartZmqTransport("Abc.Testing.Sender");

            var receivedMessageCount = 0;
            var receiverTransport = CreateAndStartZmqTransport("Abc.Testing.Receiver", _ => ++receivedMessageCount);
            var receivers = new[] { new Peer(receiverTransport.PeerId, receiverTransport.InboundEndPoint) };

            var transportMessage = new FakeCommand(42).ToTransportMessage();
            senderTransport.Send(transportMessage, receivers);

            var spinWait = new SpinWait();
            while (receivedMessageCount != 1)
                spinWait.SpinOnce();

            using (Measure.Throughput(sendMessageCount))
            {
                for (var i = 0; i < sendMessageCount; ++i)
                {
                    senderTransport.Send(transportMessage, receivers);
                }

                while (receivedMessageCount != sendMessageCount + 1)
                    spinWait.SpinOnce();
            }

            senderTransport.Stop();
            receiverTransport.Stop();
        }
예제 #2
0
        public void PerformSpinWait()
        {
            if (File.Exists(_fileName))
            {
                File.Delete(_fileName);
            }

            System.Threading.SpinWait    spinWait  = new System.Threading.SpinWait();
            System.Diagnostics.Stopwatch stopwatch = new System.Diagnostics.Stopwatch();
            int limit = 1000;

            for (int count = 0; count < 10; count++)
            {
                for (int i = 0; i <= limit; i++)
                {
                    if (i == 0)
                    {
                        Task.Run(() => WriteToFile(ref spinWait));
                    }
                    spinWait.SpinOnce();
                }
            }

            stopwatch.Start();
            spinWait.SpinOnce();
            stopwatch.Stop();
            Console.WriteLine($"Ein Spin dauerte {stopwatch.Elapsed} sekunden. Insgesamt wurden {spinWait.Count - 1} spins benötigt.");

            DetermineExactSpinCount();
        }
예제 #3
0
		public void WaitAnyTest()
		{
			ParallelTestHelper.Repeat (delegate {
				int flag = 0;
				int finished = 0;
				
				InitWithDelegate(delegate {
					int times = Interlocked.Exchange (ref flag, 1);
					if (times == 1) {
						SpinWait sw = new SpinWait ();
						while (finished == 0) sw.SpinOnce ();
					} else {
						Interlocked.Increment (ref finished);
					}
				});
				
				int index = Task.WaitAny(tasks);
				
				Assert.IsTrue (flag == 1, "#1");
				Assert.AreEqual (1, finished, "#2");
				Assert.AreNotEqual (-1, index, "#3");
				
				Task.WaitAll (tasks);
			});
		}
        /// <summary>
        /// Wait for the given sequence to be available with a timeout specified.
        /// </summary>
        /// <param name="sequence">sequence to be waited on.</param>
        /// <param name="cursor">cursor on which to wait.</param>
        /// <param name="dependents">dependents further back the chain that must advance first</param>
        /// <param name="barrier">barrier the processor is waiting on.</param>
        /// <param name="timeout">timeout value to abort after.</param>
        /// <returns>the sequence that is available which may be greater than the requested sequence.</returns>
        /// <exception cref="AlertException">AlertException if the status of the Disruptor has changed.</exception>
        public long WaitFor(long sequence, Sequence cursor, Sequence[] dependents, ISequenceBarrier barrier, TimeSpan timeout)
        {
            long availableSequence;
            var spinWait = new SpinWait();
            var sw = Stopwatch.StartNew();

            if (dependents.Length == 0)
            {
                while ((availableSequence = cursor.Value) < sequence) // volatile read
                {
                    barrier.CheckAlert();
                    spinWait.SpinOnce();

                    if (sw.Elapsed > timeout)
                    {
                        break;
                    }
                }
            }
            else
            {
                while ((availableSequence = Util.GetMinimumSequence(dependents)) < sequence)
                {
                    barrier.CheckAlert();
                    spinWait.SpinOnce();

                    if (sw.Elapsed > timeout)
                    {
                        break;
                    }
                }
            }

            return availableSequence;
        }
예제 #5
0
    // Demonstrates: 
    //      SpinWait construction 
    //      SpinWait.SpinOnce() 
    //      SpinWait.NextSpinWillYield 
    //      SpinWait.Count 
    static void Main(){
        bool someBoolean = false;
        int  numYields   = 0;

        // First task: SpinWait until someBoolean is set to true
        Task t1 = Task.Factory.StartNew(() =>
            {
                SpinWait sw = new SpinWait();
                while (!someBoolean)
                {
                    // The NextSpinWillYield property returns true if 
                    // calling sw.SpinOnce() will result in yielding the 
                    // processor instead of simply spinning. 
                    if (sw.NextSpinWillYield) numYields++;
                    sw.SpinOnce();
                }

                // As of .NET Framework 4: After some initial spinning, 
                // SpinWait.SpinOnce() will yield every time.
                Console.WriteLine("SpinWait called {0} times, yielded {1} times", 
                                  sw.Count, numYields);
            });

        // Second task: Wait 100ms, then set someBoolean to true
        Task t2 = Task.Factory.StartNew(() =>
            {
                Thread.Sleep(100);
                someBoolean = true;
            });

        // Wait for tasks to complete
        Task.WaitAll(t1, t2);
    }
예제 #6
0
        public static void ExclusiveLock(int lockId, Action method)
        {
            try
            {
                var spinWait = new SpinWait();
                while (true)
                {
                    int updVal = Interlocked.CompareExchange(ref currentlyHeldLockId, lockId, 0);
                    if (0 != updVal) break;
                    spinWait.SpinOnce();
                }
                exclusiveLockActive = true;

                if (currentlyHeldLockId == lockId)
                    method();

            }
            finally
            {
                exclusiveLockActive = false;

                if (currentlyHeldLockId == lockId)
                    currentlyHeldLockId = 0;
            }
        }
예제 #7
0
 public void WaitUntil(Func<bool> test)
 {
     SpinWait sw = new SpinWait();
     int count = 0;
     do
     {
         sw.SpinOnce();
         if (test())
             return;
     } while (!sw.NextSpinWillYield || ++count < 4);
     int? effect = null;
     try
     {
         try {} finally
         {
             effect = Interlocked.Increment(ref _lockers);
         }
         lock (this)
         {
             while (!test())
                 Monitor.Wait(this);
         }
     }
     finally
     {
         if (effect.HasValue)
             Interlocked.Decrement(ref _lockers);
     }
 }
예제 #8
0
        protected void InternalSend(ISocketSession session, IList<ArraySegment<byte>> segments)
        {
            if (!session.CanSend())
                return;

            if (InternalTrySend(session, segments))
                return;

            var sendTimeOut = m_SendTimeOut;

            //Don't retry, timeout directly
            if (sendTimeOut < 0)
            {
                throw new TimeoutException("The sending attempt timed out");
            }

            var timeOutTime = sendTimeOut > 0 ? DateTime.Now.AddMilliseconds(sendTimeOut) : DateTime.Now;

            var spinWait = new SpinWait();

            while (session.CanSend())
            {
                spinWait.SpinOnce();

                if (InternalTrySend(session, segments))
                    return;

                //If sendTimeOut = 0, don't have timeout check
                if (sendTimeOut > 0 && DateTime.Now >= timeOutTime)
                {
                    throw new TimeoutException("The sending attempt timed out");
                }
            }
        }
		public bool ExecuteThreadSafeOnce()
		{
			if (state == Initialized)
			{
				return false;
			}
			var inProgressByThisThread = Thread.CurrentThread.ManagedThreadId;
			var preexistingState = Interlocked.CompareExchange(ref state, inProgressByThisThread, NotInitialized);
			if (preexistingState == NotInitialized)
			{
				return true;
			}
			if (preexistingState == Initialized || preexistingState == inProgressByThisThread)
			{
				return false;
			}
#if DOTNET40
			var spinWait = new SpinWait();
			while (state != Initialized)
			{
				spinWait.SpinOnce();
			}
#else
			while (state != Initialized)
			{
				Thread.SpinWait(5);
			}
#endif
			return false;
		}
        // there may be some leak while increasing cap
        // but it's ok...
        public void Free(object t)
        {
            if (t == null)
            {
                return;
            }


            _factory.DestroyObject(t);
            Interlocked.Increment(ref FreeCount);
            if (_pool.Count < _pool.Capacity - 5)
            {
#if NET_2_0
                Core.Utils.SpinWait spin = new Core.Utils.SpinWait();
#else
                System.Threading.SpinWait spin = new System.Threading.SpinWait();
#endif
                while (Interlocked.Increment(ref _freeNumber) != 1)
                {
                    Interlocked.Decrement(ref _freeNumber);
                    spin.SpinOnce();
                }
                _pool.Enqueue(t);
                Interlocked.Decrement(ref _freeNumber);
            }
            else
            {
                RingBuffer <object> old = _pool;
                _pool = new RingBuffer <object>(old.Capacity * 2);
                Debug.Print("ring buffer not big enough for object pool of type {0}", _factory.MakeObject().GetType());
            }
        }
        public object Allocate()
        {
            Interlocked.Increment(ref AllocCount);

#if (NET_2_0)
            Core.Utils.SpinWait spin = new Core.Utils.SpinWait();
#else
            System.Threading.SpinWait spin = new System.Threading.SpinWait();
#endif
            while (Interlocked.Increment(ref _allocatorNumber) != 1)
            {
                Interlocked.Decrement(ref _allocatorNumber);
                spin.SpinOnce();
            }
            object obj;
            var    succ = _pool.TryDequeue(out obj);
            Interlocked.Decrement(ref _allocatorNumber);
            if (!succ || obj == null)
            {
                Interlocked.Increment(ref NewCount);
                obj = _factory.MakeObject();
            }

            _factory.ActivateObject(obj);
            return(obj);
        }
예제 #12
0
        /// <summary>
        /// Wait Event State to Set 
        /// </summary>
        public void Wait() {
            if(IsDebugEnabled)
                log.Debug("Wait event state to SET...");

            var spinWait = new System.Threading.SpinWait();
            var spinCount = 0;

            while(_state == UN_SET) {
                if(spinCount++ < SpinCount) {
                    spinWait.SpinOnce();

                    if(_eventObj == null) {
                        var mre = new ManualResetEvent(_state == SET);

                        if(Interlocked.CompareExchange(ref _eventObj, mre, null) != null) {
                            // If someone set the flag before seeing the new event object, we must ensure it's been set.
                            if(_state == SET)
                                _eventObj.Set();
                                // Lost the race w/ another thread. Just use its event.
                            else
                                mre.Close();
                        }
                        if(_eventObj != null)
                            _eventObj.WaitOne();
                    }
                }
            }
        }
예제 #13
0
        public static void RunSpinWaitTests()
        {
            SpinWait spinner = new SpinWait();

            spinner.SpinOnce();
            Assert.Equal(spinner.Count, 1);
        }
        //SpinWait 每20次会有一次系统时间片切换
        //清理数据(挂的时候数据一致性是问题,全部删掉)
        //然后相当于获取锁往下执行
        //测试发现Count=10w时,wait时间为5s
        private void TryEnterLock()
        {
            SpinWait wait = new SpinWait();
            int head = *_head;
            int tail = *_tail;
            int count = 0;

            while (Interlocked.CompareExchange(ref *_lck, 1, 0) != 0)
            {
                wait.SpinOnce();

                count++;
                if (head != *_head || tail != *_tail)
                {
                    head = *_head;
                    tail = *_tail;
                    count = 0;
                }

                if (count > 100000)
                {
                    Console.WriteLine("ClearData");
                    _ms.ClearData();
                    break;
                }
            }
        }
예제 #15
0
        public void Enter()
        {
            //如果调用线程已拥有锁,递增递归计数并返回
            Int32 threadId = Thread.CurrentThread.ManagedThreadId;
            if (threadId == m_owningThreadId) { m_recursion++; return; }

            //调用线程不拥有锁,尝试获取它
            SpinWait spinwait = new SpinWait();
            for (Int32 spincount = 0; spincount < m_spincount; spincount++)
            {
                //如果锁可以自由使用,这个线程就获得它:设置一些状态并返回
                if (Interlocked.CompareExchange(ref m_waiters, 1, 0) == 0) goto GotLock;

                //Black magic:给其它线程运行的机会,希望锁会释放。
                spinwait.SpinOnce();
            }

            //自旋(Spinning)结束,锁仍然没有获得,再试一次
            if (Interlocked.Increment(ref m_waiters) > 1)
            {
                //其它线程阻塞,这个线程也必须阻塞
                m_waiterlock.WaitOne();//等待锁:性能损失
                //等这个线程醒来时,它拥有锁:设置一些状态并返回。
            }

            GotLock:
            //一个线程拥有锁时,我们记录它的ID,并
            //指出线程拥有锁一次
            m_owningThreadId = threadId; m_recursion = 1;
        }
예제 #16
0
 public void StartNext(CompletionLink next) {
    var spinner = new SpinWait();
    while (!current._RestartWith(next)) {
       spinner.SpinOnce();
    }
    next._Start();
    current = next;
 }
        /// <summary>
        /// read lock must be aquired prior to calling this!!! we do not check it !!!!
        /// </summary>
        public void UpgradeToWrite()
        {
            var w = new SpinWait();

            while (1 != Interlocked.CompareExchange(ref _lock, _writerLock + 1, 1))
            {
                w.SpinOnce();
            }
        }
        public void EnterWriteLock()
        {
            var w = new SpinWait();

            while (0 != Interlocked.CompareExchange(ref _lock, _writerLock, 0))
            {
                w.SpinOnce();
            }
        }
예제 #19
0
		protected void WaitForStatus()
		{
			if (GetIsCompleted())
				return;

			SpinWait wait = new SpinWait();
			while (!GetIsCompleted())
				wait.SpinOnce();
		}
예제 #20
0
        public void Wait()
        {
            SpinWait wait = new SpinWait();

            wait.SpinOnce();

            while (Count > 0)
                Thread.Sleep(1);
        }
예제 #21
0
        public bool TryAdd(T item)
        {
            item.ShouldNotBeDefault("item");

            if (IsDebugEnabled)
            {
                log.Debug("요소 추가를 시도합니다... item=[{0}]", item);
            }

            CleanArrays();
            var topLayer = GetRandomLevel(ref _randomSeed);
            var v        = @getKey.Invoke(item);

            while (true)
            {
                var found = FindNode(v, _preds, _succs);

                if (found != -1)
                {
                    var nodeFound = _succs[found];

                    if (nodeFound.Marked == false)
                    {
                        var sw = new System.Threading.SpinWait();
                        while (nodeFound.FullyLinked == false)
                        {
                            sw.SpinOnce();
                        }
                        return(false);
                    }
                    continue;
                }
                var highestLocked = -1;
                try {
                    var valid = LockNodes(topLayer, ref highestLocked,
                                          (layer, pred, succ) => !pred.Marked && !succ.Marked && pred.Nexts[layer] == succ);
                    if (!valid)
                    {
                        continue;
                    }

                    var newNode = new Node(v, item, topLayer);
                    for (var layer = 0; layer <= topLayer; layer++)
                    {
                        newNode.Nexts[layer]       = _succs[layer];
                        _preds[layer].Nexts[layer] = newNode;
                    }
                    newNode.FullyLinked = true;
                }
                finally {
                    Unlock(_preds, highestLocked);
                }
                Interlocked.Increment(ref _count);
                return(true);
            }
        }
예제 #22
0
        public void Spin(int x)
        {
            Benchmark.Iterate(() => 
            {
                for (var spin = new SpinWait(); spin.Count < x; spin.SpinOnce())
                {

                }
            });
        }
예제 #23
0
        private void EndlessLoop(CancellationToken token)
        {
            var wait = new System.Threading.SpinWait();

            while (!token.IsCancellationRequested)
            {
                //do smth
                wait.SpinOnce(100);
            }
        }
예제 #24
0
        /// <summary>
        /// Enters the lock in write mode.
        /// </summary>
        /// <remarks>
        /// Upon successful acquisition of a write lock, use the <c>finally</c> block of a <c>try/finally</c> statement to call <see cref="ExitWriteLock"/>.
        /// One <see cref="ExitWriteLock"/> should be called for each <see cref="EnterWriteLock"/>.
        /// </remarks>
        public void EnterWriteLock()
        {
            SpinWait sw = new SpinWait();

            while (true)
            {
                if (m_writer == 0 && Interlocked.Exchange(ref m_writer, 1) == 0)
                {
                    // We now hold the write lock, and prevent new readers -
                    // but we must ensure no readers exist before proceeding.
                    while (m_readers != 0)
                        sw.SpinOnce();

                    break;
                }

                // We failed to take the write lock; wait a bit and retry.
                sw.SpinOnce();
            }
        }
 public void EnterReadLock()
 {
     var w = new SpinWait();
     var tmpLock = _lock;
     while (tmpLock >= _writerLock ||
         tmpLock != Interlocked.CompareExchange(ref _lock, tmpLock + 1, tmpLock))
     {
         w.SpinOnce();
         tmpLock = _lock;
     }
 }
예제 #26
0
파일: Locks.cs 프로젝트: Baptista/PC
	public void Enter() {
		SpinWait sw = new SpinWait();
		
		do {
			if (state == FREE && Interlocked.Exchange(ref state, BUSY) == BUSY) {
				return;
			}
			do {
				sw.SpinOnce();
			} while (state == BUSY);
		} while (true);
	}
예제 #27
0
        /// <summary>
        /// Increments a value whilst keeping it inside a range.
        /// </summary>
        /// <param name="value">The value.</param>
        /// <param name="start">The start of the range (inclusive).</param>
        /// <param name="end">The end of the range (inclusive).</param>
        /// <returns>The incremented result.</returns>
        public static int Increment(ref int value, int start, int end)
        {
            SpinWait spinWait = new SpinWait();
            do
            {
                int v = value;
                if (Interlocked.CompareExchange(ref value, v >= end ? start : v + 1, v) == v)
                    return v;

                spinWait.SpinOnce();
            } while (true);
        }
예제 #28
0
        public static bool SpinUntil(Func<bool> condition, int millisecondsTimeout) {
            SpinWait sw = new SpinWait();
            Watch watch = Watch.StartNew();

            while (!condition()) {
                if (watch.ElapsedMilliseconds > millisecondsTimeout)
                    return false;
                sw.SpinOnce();
            }

            return true;
        }
 private bool TryCompletion(){
     SpinWait sw = new SpinWait();
     do
     {
         int p;
         if ((p = _permits) == 0) return false;
         
         if (Interlocked.CompareExchange(ref _permits, p - 1, p) == p) return true;
        
         sw.SpinOnce();
     } while (true);
 }
예제 #30
0
 public bool Wait(int millisecondsTimeout)
 {
     while (Interlocked.CompareExchange(ref mStatus, 0, -1) != -1)
     {
         mSpinWait.SpinOnce();
         if (IsCompleted)
         {
             return(true);
         }
     }
     return(mResetEvent.WaitOne(millisecondsTimeout));
 }
예제 #31
0
        public WaitGroupEventEnum WaitAny(
            long microsecondsToAwake
            )
        {
            var result = WaitGroupEventEnum.WaitTimeout;

            var spinWait = new SpinWait();

            while (true)
            {
                var stopRaised = Interlocked.Read(ref _stopRaised);
                if (stopRaised > 0L)
                {
                    //stopRaised - is a 'manual' event
                    //no decrement at all!

                    result = WaitGroupEventEnum.Stop;

                    break;
                }

                //restartRaised - is an 'auto' event , so we need to 'reset' the event
                var restartRaised = Interlocked.Exchange(ref _restartRaised, 0L);
                if (restartRaised > 0L)
                {
                    result = WaitGroupEventEnum.Restart;

                    break;
                }

                //если ждать не надо, сразу выходим
                if (microsecondsToAwake == 0)
                {
                    break;
                }

                //проверяем не истек ли таймаут только когда таймаут задан
                if (microsecondsToAwake > 0)
                {
                    if (microsecondsToAwake <= _performanceTimer.MicroSeconds)
                    {
                        //сработал таймаут
                        break;
                    }
                }

                spinWait.SpinOnce();
            }

            return
                result;
        }
예제 #32
0
파일: SpinWait.cs 프로젝트: tgiphil/mono
		public static bool SpinUntil (Func<bool> predicate, int milliseconds)
		{
			SpinWait sw = new SpinWait ();
			Watch watch = Watch.StartNew ();

			while (!predicate ()) {
				if (watch.ElapsedMilliseconds > milliseconds)
					return false;
				sw.SpinOnce ();
			}

			return true;
		}
        /// <summary>
        /// <see cref="IWaitStrategy.WaitFor"/>
        /// </summary>
        public long WaitFor(long sequence, Sequence cursor, ISequence dependentSequence, ISequenceBarrier barrier)
        {
            long availableSequence;

            var spinWait = new SpinWait();
            while ((availableSequence = dependentSequence.Value) < sequence)
            {
                barrier.CheckAlert();
                spinWait.SpinOnce();
            }

            return availableSequence;
        }
예제 #34
0
    public void TestGetItemThreadSafety()
    {
        int i1 = 0x10;
        int i2 = 0x100;
        long l1;
        long l2;

        //Setup key1 and key2 so they are different values but have the same hashcode
        //To produce a hashcode long XOR's the first 32bits with the last 32 bits
        l1 = (((long) i1) << 32) + i2;
        l2 = (((long) i2) << 32) + i1;
        _key1 = (object) l1;
        _key2 = (object) l2;

        _ht = new Hashtable(3); //Just one item will be in the hashtable at a time
        int taskCount = 3;
        Task[] readers1 = new Task[taskCount];
        Task[] readers2 = new Task[taskCount];
        Task writer;

        Stopwatch stopwatch = Stopwatch.StartNew();

        for (int i = 0; i < readers1.Length; i++)
        {
            readers1[i] = Task.Run(new Action(ReaderFunction1));
        }

        for (int i = 0; i < readers2.Length; i++)
        {
            readers2[i] = Task.Run(new Action(ReaderFunction2));
        }

        writer = Task.Run(new Action(WriterFunction));

        SpinWait spin = new SpinWait();
        while (!_errorOccurred && !_timeExpired)
        {
            if (MAX_TEST_TIME_MS < stopwatch.ElapsedMilliseconds)
            {
                _timeExpired = true;
            }

            spin.SpinOnce();
        }

        Task.WaitAll(readers1);
        Task.WaitAll(readers2);
        writer.Wait();

        Assert.False(_errorOccurred);
    }
예제 #35
0
        public void TestFastBatchEnqueueDequeue()
        {
            int count = 1000;

            var source = new string[count * 3];

            for (var i = 0; i < source.Length; i++)
            {
                source[i] = Guid.NewGuid().ToString();
            }

            IBatchQueue<string> queue = new ConcurrentBatchQueue<string>(count * 3);

            Task[] tasks = new Task[count];

            for (var i = 0; i < count; i++)
            {
                tasks[i] = new Task((j) =>
                {
                    var index = (int)j;
                    queue.Enqueue(new string[] { source[index * 3], source[index * 3 + 1], source[index * 3 + 2] });
                }, i);
            }

            tasks.ToList().ForEach(t => t.Start());

            var outputList = new List<string>();

            var spinWait = new SpinWait();

            while (outputList.Count < source.Length)
            {
                if (!queue.TryDequeue(outputList))
                    spinWait.SpinOnce();
                else
                    Console.WriteLine("Count:" + outputList.Count);
            }

            var dict = source.ToDictionary(s => s);

            for (var i = 0; i < outputList.Count; i++)
            {
                var line = outputList[i];

                if (!dict.Remove(line))
                    Assert.Fail("Dequeue error");
            }

            Assert.AreEqual(0, dict.Count);
        }
예제 #36
0
        private IEnumerable <T> GetAllItems()
        {
            Node curr = _leftSentinel;

            while ((curr = curr.Nexts[0]) != _rightSentinel)
            {
                var sw = new System.Threading.SpinWait();

                while (curr.FullyLinked == false)
                {
                    sw.SpinOnce();
                }
                yield return(curr.Value);
            }
        }
예제 #37
0
        /// <summary>
        /// Causes a thread to wait the number of times defined by the iterations parameter.
        /// </summary>
        /// <param name="iterations">The number of iterations.</param>
        public static void SpinWait(int iterations)
        {
#if NETFX_CORE
            var spinWait = new SpinWait();

            while (spinWait.Count < iterations)
            {
                spinWait.SpinOnce();
            }
#elif PCL
            Sleep(1); // alternative for PCL
#else
            Thread.SpinWait(20);
#endif
        }
예제 #38
0
        // Helper function to send an entire test sequence fast (no RX, no open/close of serial)
        //public void Send_test_sequence_fast(byte[] tx_buf, SerialPort fpga_com_port)
        //{
        // Open Serial Port
        //SerialPort fpga_com_port = setup_serial_port();
        // Send Data
        //Send_serial_data_turbo(tx_buf, fpga_com_port);
        // Rx Reply
        //string rx_string = Read_serial_data(fpga_com_port);
        // Print
        //Debug.WriteLine("Write: 0x" + tx_string);
        //Debug.WriteLine("Read:  0x" + rx_string);
        //Debug.WriteLine("Data Equal: " + tx_string.Equals(rx_string));
        // Close Serial Port
        //close_serial_port(fpga_com_port);

        //}

        // Helper function allow us to sleep with microsecond resolution but burns through CPU clock cycles as spin-locks rather than sleeps
        // Needs this as Windows scheduler only works at the 13ms resolution
        // This function shall allow us to specify a microsecond and achieve timing with max error of about 30 uS overshoot (worst-case seen in practice)
        // Perfect for our application where we want timing accurate to about 0.1mS
        public void high_resolution_sleep_us(UInt32 wait_time_in_microseconds)
        {
            //// Make sure we are using the High Performance Stopwatch
            //if (Stopwatch.IsHighResolution)
            //{
            //    Console.WriteLine("Operations timed using the system's high-resolution performance counter.");
            //}
            //else
            //{
            //    Console.WriteLine("Operations timed using the DateTime class.");
            //}

            // Where we are now
            Stopwatch my_stopwatch = Stopwatch.StartNew();
            //long starting_timestamp = Stopwatch.GetTimestamp();
            // Where we want to get to, we count this using ticks rather than timestamps as more precise and its how the API works
            long nano_sec_per_tick = (1000L * 1000L * 1000L) / Stopwatch.Frequency;       // Ony my PC, observed that this was 100 nanosec/tick => Our timer has a 10 MHz tick rate, nice, plenty for microsecond resolution
            long ticks_to_wait     = (wait_time_in_microseconds * 1000L) / nano_sec_per_tick;
            long starting_ticks    = my_stopwatch.ElapsedTicks;
            long target_ticks      = starting_ticks + ticks_to_wait;
            // Use a spin-lock structure for no-ops to get our timing - .Net way of doing this
            SpinWait spin_locker = new System.Threading.SpinWait();
            long     tick_count  = my_stopwatch.ElapsedTicks;

            while (tick_count < target_ticks)
            {
                // Spin-Lock until we have reached our tips target
                tick_count = my_stopwatch.ElapsedTicks;
                spin_locker.SpinOnce();
                // Want't good timing, so reset spin_locker before it goes into a longer sleep
                if (spin_locker.NextSpinWillYield)
                {
                    spin_locker.Reset();
                }
                //Console.WriteLine("Ticks: " + tick_count);
            }
            //spin_locker(  )1
            // Now check how long it took for debugging
            long ending_ticks  = my_stopwatch.ElapsedTicks;
            long elapsed_ticks = ending_ticks - starting_ticks;
            //double ElapsedSeconds = elapsed_ticks * (1.0 / Stopwatch.Frequency);
            double ElapsedMicroSeconds = elapsed_ticks * (nano_sec_per_tick / 1000.0); // ORdered like this to not lose precision due to truncations
            //Console.WriteLine("Elapsed Microseconds: " + ElapsedMicroSeconds);
        }
예제 #39
0
 private bool do_Process(ConcurrentQueue <T> mq, int x)
 {
     spin.Reset();
     while (!mq.IsEmpty)
     {
         T msg;
         while (mq.TryPeek(out msg))
         {
             IsProcessSuccess = true;
             try
             {
                 messageArg.Message = msg;
                 OnMessageComing(messageArg);
             }
             finally
             {
                 if (IsProcessSuccess)
                 {
                     tryCount = 0;
                     mq.TryDequeue(out msg);
                 }
                 else
                 {
                     tryCount++;
                     if (tryCount >= MaxTryCount)
                     {
                         tryCount = 0;
                         mq.TryDequeue(out msg);
                     }
                 }
             }
             if (spin.Count >= SpinRate * x)
             {
                 return(false);
             }
             spin.SpinOnce();
         }
     }
     return(false);
 }
예제 #40
0
        /// <summary>
        /// 최상위 요소를 스택에서 꺼냅니다.
        /// </summary>
        /// <returns></returns>
        public T Pop()
        {
            if (IsDebugEnabled)
            {
                log.Debug("최상위 요소를 스택에서 꺼냅니다...");
            }

            StackNode <T> current;
            var           spinWait = new System.Threading.SpinWait();


            while (true)
            {
                StackNode <T> next;
                do
                {
                    current = _head;
                    if (current == null)
                    {
                        break;
                    }
                    next = current.Next;
#pragma warning disable 0420
                } while(_head != current || Interlocked.CompareExchange(ref _head, next, current) != current);
#pragma warning restore 0420

                if (current != null)
                {
                    break;
                }
                spinWait.SpinOnce();
            }

            if (IsDebugEnabled)
            {
                log.Debug("스택에서 요소를 꺼냈습니다. item=[{0}]", current.Item);
            }

            return(current.Item);
        }
예제 #41
0
        private void DetermineExactSpinCount()
        {
            System.Threading.SpinWait spin = new System.Threading.SpinWait();
            int limit = 0;

            while (true)
            {
                try
                {
                    for (int count = 0; count < 100; count++)
                    {
                        for (int i = 0; i <= limit; i++)
                        {
                            if (i == 0)
                            {
                                Task.Run(() =>
                                {
                                    try
                                    {
                                        WriteToFile(ref spin);
                                    }
                                    catch (IOException)
                                    {
                                        limit++;
                                    }
                                });
                            }
                            spin.SpinOnce();
                        }
                    }
                }
                catch (IOException)
                {
                    limit++;
                }
                break;
            }
            Console.WriteLine($"Es braucht min {spin.Count} spins um eine IOException zu verhindern.");
        }
예제 #42
0
        public void Reset()
        {
            var spinWait = new SpinWait();

            while (true)
            {
                var status = (Status)Volatile.Read(ref _status);
                switch (status)
                {
                case Status.Disposed:
                    // Disposed
                    throw new ObjectDisposedException(nameof(ManualResetEventSlim));

                case Status.NotSet:
                case Status.HandleRequestedNotSet:
                case Status.HandleReadyNotSet:
                    // Nothing to do
                    return;

                case Status.Set:
                    // Reset if Set
                    status = (Status)Interlocked.CompareExchange(ref _status, (int)Status.NotSet, (int)Status.Set);
                    if (status == Status.NotSet || status == Status.Set)
                    {
                        // We Reset it or it was already Reset
                        // Either way, we are done
                        return;
                    }

                    // Must has been disposed, or the wait handle requested
                    break;

                case Status.HandleRequestedSet:
                    // Another thread is creating the wait handle
                    // SpinWait
                    break;

                case Status.HandleReadySet:
                    // Reset if Set
                    status = (Status)Interlocked.CompareExchange(ref _status, (int)Status.HandleReadyNotSet, (int)Status.HandleReadySet);
                    switch (status)
                    {
                    case Status.HandleReadySet:
                    {
                        // We reset it
                        // Update the wait handle
                        var handle = Volatile.Read(ref _handle);
                        if (handle != null)
                        {
                            // Reset it
                            handle.Reset();
                            // Done
                            return;
                        }

                        break;
                    }

                    case Status.HandleReadyNotSet:
                        // Another thread reset it
                        // we are done
                        return;

                    default:
                        break;
                    }

                    // Probably Disposed
                    break;

                default:
                    // Should not happen
                    break;
                }

                spinWait.SpinOnce();
            }
        }
예제 #43
0
        private ManualResetEvent GetOrCreateWaitHandle()
        {
            // At the end of this method: _status will be (int)Status.HandleCreated or ObjectDisposedException is thrown
            var spinWait = new SpinWait();

            while (true)
            {
                var status = (Status)Volatile.Read(ref _status);
                switch (status)
                {
                case Status.Disposed:
                    // Disposed
                    throw new ObjectDisposedException(nameof(ManualResetEventSlim));

                case Status.NotSet:
                    // Indicate we will be creating the handle
                    status = (Status)Interlocked.CompareExchange(ref _status, (int)Status.HandleRequestedNotSet, (int)status);
                    if (status == Status.NotSet)
                    {
                        // Create the handle
                        var created = new ManualResetEvent(false);
                        // Set the handle
                        Volatile.Write(ref _handle, created);
                        // Notify that the handle is ready
                        Volatile.Write(ref _status, (int)Status.HandleReadyNotSet);
                        // Return the handle we created
                        return(created);
                    }

                    // Must has been disposed, or another thread is creating the handle
                    break;

                case Status.Set:
                    // Indicate we will be creating the handle
                    status = (Status)Interlocked.CompareExchange(ref _status, (int)Status.HandleRequestedSet, (int)status);
                    if (status == Status.Set)
                    {
                        // Create the handle
                        var created = new ManualResetEvent(true);
                        // Set the handle
                        Volatile.Write(ref _handle, created);
                        // Notify that the handle is ready
                        Volatile.Write(ref _status, (int)Status.HandleReadySet);
                        // Return the handle we created
                        return(created);
                    }

                    // Must has been disposed, or another thread is creating the handle
                    break;

                case Status.HandleRequestedNotSet:
                case Status.HandleRequestedSet:
                    // Another thread is creating the wait handle
                    // SpinWait
                    break;

                case Status.HandleReadyNotSet:
                case Status.HandleReadySet:
                    // The handle already exists
                    // Get the handle that is already created
                    var handle = Volatile.Read(ref _handle);
                    if (handle != null)
                    {
                        // Return it
                        return(handle);
                    }

                    // Probably Disposed
                    break;

                default:
                    // Should not happen
                    break;
                }

                spinWait.SpinOnce();
            }
        }
예제 #44
0
        public void Set()
        {
            var spinWait = new SpinWait();

            while (true)
            {
                var status = (Status)Thread.VolatileRead(ref _status);
                switch (status)
                {
                case Status.Disposed:
                    // Disposed
                    // Fail sailently
                    return;

                case Status.NotSet:
                    // Set if Reset
                    status = (Status)Interlocked.CompareExchange(ref _status, (int)Status.Set, (int)Status.NotSet);
                    if (status == Status.NotSet || status == Status.Set)
                    {
                        // We Set it or it was already Set
                        // Either way, we are done
                        return;
                    }
                    // Must has been disposed, or the wait handle requested
                    break;

                case Status.Set:
                    // Nothing to do
                    return;

                case Status.HandleRequested:
                    // Another thread is creating the wait handle
                    // SpinWait
                    break;

                case Status.HandleReadyNotSet:
                    // Set if Reset
                    status = (Status)Interlocked.CompareExchange(ref _status, (int)Status.HandleReadySet, (int)Status.HandleReadyNotSet);
                    if (status == Status.HandleReadyNotSet)
                    {
                        // We set it
                        // Update the wait handle
                        var handle = Volatile.Read(ref _handle);
                        if (handle != null)
                        {
                            // Reset it
                            handle.Set();
                            // Done
                            return;
                        }
                    }
                    if (status == Status.HandleReadySet)
                    {
                        // Another thread set it
                        // we are done
                        return;
                    }
                    // Probably Disposed
                    break;

                case Status.HandleReadySet:
                    // Nothing to do
                    return;

                default:
                    // Should not happen
                    break;
                }
                spinWait.SpinOnce();
            }
        }
예제 #45
0
        /// <summary>
        /// Notifies the <see cref="Barrier"/> that there will be additional participants.
        /// </summary>
        /// <param name="participantCount">The number of additional participants to add to the
        /// barrier.</param>
        /// <returns>The phase number of the barrier in which the new participants will first
        /// participate.</returns>
        /// <exception cref="T:System.ArgumentOutOfRangeException"><paramref name="participantCount"/> is less than
        /// 0.</exception>
        /// <exception cref="T:System.ArgumentOutOfRangeException">Adding <paramref name="participantCount"/> participants would cause the
        /// barrier's participant count to exceed <see cref="T:System.Int16.MaxValue"/>.</exception>
        /// <exception cref="T:System.InvalidOperationException">
        /// The method was invoked from within a post-phase action.
        /// </exception>
        /// <exception cref="T:System.ObjectDisposedException">The current instance has already been
        /// disposed.</exception>
        public long AddParticipants(int participantCount)
        {
            // check dispose
            ThrowIfDisposed();

            if (participantCount < 1)
            {
                throw new ArgumentOutOfRangeException("participantCount", participantCount, "The participantCount argument must be a positive value.");
            }
            else if (participantCount > Max_Participants) //overflow
            {
                throw new ArgumentOutOfRangeException("participantCount", "Adding participantCount participants would result in the number of participants exceeding the maximum number allowed.");
            }

            // in case of this is called from the PHA
            if (_actionCallerId != 0 && Thread.CurrentThread.ManagedThreadId == _actionCallerId)
            {
                throw new InvalidOperationException("This method may not be called from within the postPhaseAction.");
            }

            var  spinner = new SpinWait();
            long newPhase;

            while (true)
            {
                var  currentTotal = Thread.VolatileRead(ref _currentTotalCount);
                int  total;
                int  current;
                bool sense;
                GetCurrentTotal(currentTotal, out current, out total, out sense);
                if (participantCount + total > Max_Participants) //overflow
                {
                    throw new ArgumentOutOfRangeException("participantCount", "Adding participantCount participants would result in the number of participants exceeding the maximum number allowed.");
                }

                if (SetCurrentTotal(currentTotal, current, total + participantCount, sense))
                {
                    // Calculating the first phase for that participant, if the current phase already finished return the nextphase else return the current phase
                    // To know that the current phase is  the sense doesn't match the
                    // phase odd even, so that means it didn't yet change the phase count, so currentPhase +1 is returned, otherwise currentPhase is returned
                    var currPhase = CurrentPhaseNumber;
                    newPhase = (sense != (currPhase % 2 == 0)) ? currPhase + 1 : currPhase;

                    // If this participant is going to join the next phase, which means the postPhaseAction is being running, this participants must wait until this done
                    // and its event is reset.
                    // Without that, if the postPhaseAction takes long time, this means the event ehich the current participant is goint to wait on is still set
                    // (FinishPPhase didn't reset it yet) so it should wait until it reset
                    if (newPhase != currPhase)
                    {
                        // Wait on the opposite event
                        if (sense)
                        {
                            _oddEvent.Wait();
                        }
                        else
                        {
                            _evenEvent.Wait();
                        }
                    }

                    //This else to fix the racing where the current phase has been finished, m_currentPhase has been updated but the events have not been set/reset yet
                    // otherwise when this participant calls SignalAndWait it will wait on a set event however all other participants have not arrived yet.
                    else
                    {
                        if (sense && _evenEvent.IsSet)
                        {
                            _evenEvent.Reset();
                        }
                        else if (!sense && _oddEvent.IsSet)
                        {
                            _oddEvent.Reset();
                        }
                    }
                    break;
                }
                spinner.SpinOnce();
            }
            return(newPhase);
        }
예제 #46
0
        /// <summary>
        /// Signals that a participant has reached the barrier and waits for all other participants to reach
        /// the barrier as well, 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 all other participants reached the barrier; 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 method was invoked from within a post-phase action, the barrier currently has 0 participants,
        /// or the barrier is being used by more threads than are registered as participants.
        /// </exception>
        /// <exception cref="T:System.OperationCanceledException"><paramref name="cancellationToken"/> has been
        /// canceled.</exception>
        /// <exception cref="T:System.ObjectDisposedException">The current instance has already been
        /// disposed.</exception>
        public bool SignalAndWait(int millisecondsTimeout, CancellationToken cancellationToken)
        {
            ThrowIfDisposed();
            cancellationToken.ThrowIfCancellationRequested();

            if (millisecondsTimeout < -1)
            {
                throw new ArgumentOutOfRangeException("millisecondsTimeout", millisecondsTimeout, "The specified timeout must represent a value between -1 and Int32.MaxValue, inclusive.");
            }

            // in case of this is called from the PHA
            if (_actionCallerId != 0 && Thread.CurrentThread.ManagedThreadId == _actionCallerId)
            {
                throw new InvalidOperationException("This method may not be called from within the postPhaseAction.");
            }

            // local variables to extract the basic barrier variable and update them
            // The are declared here instead of inside the loop body because the will be used outside the loop
            bool sense; // The sense of the barrier *before* the phase associated with this SignalAndWait call completes
            int  total;
            int  current;
            int  currentTotal;
            long phase;
            var  spinner = new SpinWait();

            while (true)
            {
                currentTotal = Thread.VolatileRead(ref _currentTotalCount);
                GetCurrentTotal(currentTotal, out current, out total, out sense);
                phase = CurrentPhaseNumber;
                // throw if zero participants
                if (total == 0)
                {
                    throw new InvalidOperationException("The barrier has no registered participants.");
                }
                // Try to detect if the number of threads for this phase exceeded the total number of participants or not
                // This can be detected if the current is zero which means all participants for that phase has arrived and the phase number is not changed yet
                if (current == 0 && sense != (CurrentPhaseNumber % 2 == 0))
                {
                    throw new InvalidOperationException("The number of threads using the barrier exceeded the total number of registered participants.");
                }
                //This is the last thread, finish the phase
                if (current + 1 == total)
                {
                    if (SetCurrentTotal(currentTotal, 0, total, !sense))
                    {
                        FinishPhase(sense);
                        return(true);
                    }
                }
                else if (SetCurrentTotal(currentTotal, current + 1, total, sense))
                {
                    break;
                }

                spinner.SpinOnce();
            }

            // ** Perform the real wait **
            // select the correct event to wait on, based on the current sense.
            var eventToWaitOn = (sense) ? _evenEvent : _oddEvent;

            var waitWasCanceled = false;
            var waitResult      = false;

            try
            {
                waitResult = DiscontinuousWait(eventToWaitOn, millisecondsTimeout, cancellationToken, phase);
            }
            catch (OperationCanceledException)
            {
                waitWasCanceled = true;
            }
            catch (ObjectDisposedException)// in case a ---- happen where one of the thread returned from SignalAndWait and the current thread calls Wait on a disposed event
            {
                // make sure the current phase for this thread is already finished, otherwise propagate the exception
                if (phase < CurrentPhaseNumber)
                {
                    waitResult = true;
                }
                else
                {
                    throw;
                }
            }



            if (!waitResult)
            {
                //reset the spinLock to prepare it for the next loop
                spinner.Reset();

                //If the wait timeout expired and all other thread didn't reach the barrier yet, update the current count back
                while (true)
                {
                    bool newSense;
                    currentTotal = Thread.VolatileRead(ref _currentTotalCount);
                    GetCurrentTotal(currentTotal, out current, out total, out newSense);
                    // If the timeout expired and the phase has just finished, return true and this is considered as succeeded SignalAndWait
                    //otherwise the timeout expired and the current phase has not been finished yet, return false
                    //The phase is finished if the phase member variable is changed (incremented) or the sense has been changed
                    // we have to use the statements in the comparison below for two cases:
                    // 1- The sense is changed but the last thread didn't update the phase yet
                    // 2- The phase is already incremented but the sense flipped twice due to the termination of the next phase
                    if (phase < CurrentPhaseNumber || sense != newSense)
                    {
                        // The current phase has been finished, but we shouldn't return before the events are set/reset otherwise this thread could start
                        // next phase and the appropriate event has not reset yet which could make it return immediately from the next phase SignalAndWait
                        // before waiting other threads
                        WaitCurrentPhase(eventToWaitOn, phase);
                        Debug.Assert(phase < CurrentPhaseNumber);
                        break;
                    }
                    //The phase has not been finished yet, try to update the current count.
                    if (SetCurrentTotal(currentTotal, current - 1, total, sense))
                    {
                        //if here, then the attempt to backout was successful.
                        //throw (a fresh) oce if cancellation woke the wait
                        //or return false if it was the timeout that woke the wait.
                        //
                        if (waitWasCanceled)
                        {
                            throw new NewOperationCanceledException("The operation was canceled.", cancellationToken);
                        }
                        else
                        {
                            return(false);
                        }
                    }
                    spinner.SpinOnce();
                }
            }

            if (_exception != null)
            {
                throw new BarrierPostPhaseException(_exception);
            }

            return(true);
        }
예제 #47
0
        private void ContinueTryEnter(int millisecondsTimeout, ref bool lockTaken)
        {
            int  owner;
            long startTicks = 0L;

            if ((millisecondsTimeout != -1) && (millisecondsTimeout != 0))
            {
                startTicks = DateTime.UtcNow.Ticks;
            }
            if (CdsSyncEtwBCLProvider.Log.IsEnabled())
            {
                CdsSyncEtwBCLProvider.Log.SpinLock_FastPathFailed(this.m_owner);
            }
            if (this.IsThreadOwnerTrackingEnabled)
            {
                this.ContinueTryEnterWithThreadTracking(millisecondsTimeout, startTicks, ref lockTaken);
                return;
            }
            SpinWait wait = new SpinWait();

            while (true)
            {
                owner = this.m_owner;
                if ((owner & 1) == 0)
                {
                    Thread.BeginCriticalRegion();
                    if (Interlocked.CompareExchange(ref this.m_owner, owner | 1, owner, ref lockTaken) == owner)
                    {
                        return;
                    }
                    Thread.EndCriticalRegion();
                }
                else if (((owner & 0x7ffffffe) == MAXIMUM_WAITERS) || (Interlocked.CompareExchange(ref this.m_owner, owner + 2, owner) == owner))
                {
                    break;
                }
                wait.SpinOnce();
            }
            if ((millisecondsTimeout == 0) || ((millisecondsTimeout != -1) && TimeoutExpired(startTicks, millisecondsTimeout)))
            {
                this.DecrementWaiters();
                return;
            }
            int num3           = ((owner + 2) & 0x7ffffffe) / 2;
            int processorCount = PlatformHelper.ProcessorCount;

            if (num3 < processorCount)
            {
                int num5 = 1;
                for (int i = 1; i <= (num3 * 100); i++)
                {
                    Thread.SpinWait(((num3 + i) * 100) * num5);
                    if (num5 < processorCount)
                    {
                        num5++;
                    }
                    owner = this.m_owner;
                    if ((owner & 1) == 0)
                    {
                        Thread.BeginCriticalRegion();
                        int num7 = ((owner & 0x7ffffffe) == 0) ? (owner | 1) : ((owner - 2) | 1);
                        if (Interlocked.CompareExchange(ref this.m_owner, num7, owner, ref lockTaken) == owner)
                        {
                            return;
                        }
                        Thread.EndCriticalRegion();
                    }
                }
            }
            if ((millisecondsTimeout != -1) && TimeoutExpired(startTicks, millisecondsTimeout))
            {
                this.DecrementWaiters();
                return;
            }
            int num8 = 0;

Label_015F:
            owner = this.m_owner;
            if ((owner & 1) == 0)
            {
                Thread.BeginCriticalRegion();
                int num9 = ((owner & 0x7ffffffe) == 0) ? (owner | 1) : ((owner - 2) | 1);
                if (Interlocked.CompareExchange(ref this.m_owner, num9, owner, ref lockTaken) == owner)
                {
                    return;
                }
                Thread.EndCriticalRegion();
            }
            if ((num8 % 40) == 0)
            {
                Thread.Sleep(1);
            }
            else if ((num8 % 10) == 0)
            {
                Thread.Sleep(0);
            }
            else
            {
                Thread.Yield();
            }
            if ((((num8 % 10) == 0) && (millisecondsTimeout != -1)) && TimeoutExpired(startTicks, millisecondsTimeout))
            {
                this.DecrementWaiters();
            }
            else
            {
                num8++;
                goto Label_015F;
            }
        }
        /// <summary>
        /// Notifies the <see cref="Barrier"/> that there will be additional participants.
        /// </summary>
        /// <param name="participantCount">The number of additional participants to add to the
        /// barrier.</param>
        /// <returns>The phase number of the barrier in which the new participants will first
        /// participate.</returns>
        /// <exception cref="System.ArgumentOutOfRangeException"><paramref name="participantCount"/> is less than
        /// 0.</exception>
        /// <exception cref="System.ArgumentOutOfRangeException">Adding <paramref name="participantCount"/> participants would cause the
        /// barrier's participant count to exceed <see cref="short.MaxValue"/>.</exception>
        /// <exception cref="System.InvalidOperationException">
        /// The method was invoked from within a post-phase action.
        /// </exception>
        /// <exception cref="System.ObjectDisposedException">The current instance has already been
        /// disposed.</exception>
        public long AddParticipants(int participantCount)
        {
            // check dispose
            ThrowIfDisposed();

            if (participantCount < 1)
            {
                throw new ArgumentOutOfRangeException(nameof(participantCount), participantCount,
                                                      SR.Barrier_AddParticipants_NonPositive_ArgumentOutOfRange);
            }
            else if (participantCount > MAX_PARTICIPANTS) //overflow
            {
                throw new ArgumentOutOfRangeException(nameof(participantCount),
                                                      SR.Barrier_AddParticipants_Overflow_ArgumentOutOfRange);
            }

            // in case of this is called from the PHA
            if (_actionCallerID != 0 && Environment.CurrentManagedThreadId == _actionCallerID)
            {
                throw new InvalidOperationException(SR.Barrier_InvalidOperation_CalledFromPHA);
            }

            SpinWait spinner  = default;
            long     newPhase = 0;

            while (true)
            {
                int  currentTotal = _currentTotalCount;
                int  total;
                int  current;
                bool sense;
                GetCurrentTotal(currentTotal, out current, out total, out sense);
                if (participantCount + total > MAX_PARTICIPANTS) //overflow
                {
                    throw new ArgumentOutOfRangeException(nameof(participantCount),
                                                          SR.Barrier_AddParticipants_Overflow_ArgumentOutOfRange);
                }

                if (SetCurrentTotal(currentTotal, current, total + participantCount, sense))
                {
                    // Calculating the first phase for that participant, if the current phase already finished return the next phase else return the current phase
                    // To know that the current phase is  the sense doesn't match the
                    // phase odd even, so that means it didn't yet change the phase count, so currentPhase +1 is returned, otherwise currentPhase is returned
                    long currPhase = CurrentPhaseNumber;
                    newPhase = (sense != (currPhase % 2 == 0)) ? currPhase + 1 : currPhase;

                    // If this participant is going to join the next phase, which means the postPhaseAction is being running, this participants must wait until this done
                    // and its event is reset.
                    // Without that, if the postPhaseAction takes long time, this means the event that the current participant is going to wait on is still set
                    // (FinishPhase didn't reset it yet) so it should wait until it reset
                    if (newPhase != currPhase)
                    {
                        // Wait on the opposite event
                        if (sense)
                        {
                            _oddEvent.Wait();
                        }
                        else
                        {
                            _evenEvent.Wait();
                        }
                    }

                    //This else to fix the racing where the current phase has been finished, m_currentPhase has been updated but the events have not been set/reset yet
                    // otherwise when this participant calls SignalAndWait it will wait on a set event however all other participants have not arrived yet.
                    else
                    {
                        if (sense && _evenEvent.IsSet)
                        {
                            _evenEvent.Reset();
                        }
                        else if (!sense && _oddEvent.IsSet)
                        {
                            _oddEvent.Reset();
                        }
                    }
                    break;
                }
                spinner.SpinOnce(sleep1Threshold: -1);
            }
            return(newPhase);
        }
예제 #49
0
        /// <summary>
        /// Try acquire the lock with long path, this is usually called after the first path in Enter and
        /// TryEnter failed The reason for short path is to make it inline in the run time which improves the
        /// performance. This method assumed that the parameter are validated in Enter or TryEnter method.
        /// </summary>
        /// <param name="millisecondsTimeout">The timeout milliseconds</param>
        /// <param name="lockTaken">The lockTaken param</param>
        private void ContinueTryEnter(int millisecondsTimeout, ref bool lockTaken)
        {
            // The fast path doesn't throw any exception, so we have to validate the parameters here
            if (lockTaken)
            {
                lockTaken = false;
                throw new ArgumentException(SR.SpinLock_TryReliableEnter_ArgumentException);
            }

            if (millisecondsTimeout < -1)
            {
                throw new ArgumentOutOfRangeException(
                          nameof(millisecondsTimeout), millisecondsTimeout, SR.SpinLock_TryEnter_ArgumentOutOfRange);
            }

            uint startTime = 0;

            if (millisecondsTimeout != Timeout.Infinite && millisecondsTimeout != 0)
            {
                startTime = TimeoutHelper.GetTime();
            }

            if (IsThreadOwnerTrackingEnabled)
            {
                // Slow path for enabled thread tracking mode
                ContinueTryEnterWithThreadTracking(millisecondsTimeout, startTime, ref lockTaken);
                return;
            }

            // then thread tracking is disabled
            // In this case there are three ways to acquire the lock
            // 1- the first way the thread either tries to get the lock if it's free or updates the waiters, if the turn >= the processors count then go to 3 else go to 2
            // 2- In this step the waiter threads spins and tries to acquire the lock, the number of spin iterations and spin count is dependent on the thread turn
            // the late the thread arrives the more it spins and less frequent it check the lock availability
            // Also the spins count is increases each iteration
            // If the spins iterations finished and failed to acquire the lock, go to step 3
            // 3- This is the yielding step, there are two ways of yielding Thread.Yield and Sleep(1)
            // If the timeout is expired in after step 1, we need to decrement the waiters count before returning

            int observedOwner;
            int turn = int.MaxValue;

            //***Step 1, take the lock or update the waiters

            // try to acquire the lock directly if possible or update the waiters count
            observedOwner = _owner;
            if ((observedOwner & LOCK_ANONYMOUS_OWNED) == LOCK_UNOWNED)
            {
                if (CompareExchange(ref _owner, observedOwner | 1, observedOwner, ref lockTaken) == observedOwner)
                {
                    // Acquired lock
                    return;
                }

                if (millisecondsTimeout == 0)
                {
                    // Did not acquire lock in CompareExchange and timeout is 0 so fail fast
                    return;
                }
            }
            else if (millisecondsTimeout == 0)
            {
                // Did not acquire lock as owned and timeout is 0 so fail fast
                return;
            }
            else //failed to acquire the lock, then try to update the waiters. If the waiters count reached the maximum, just break the loop to avoid overflow
            {
                if ((observedOwner & WAITERS_MASK) != MAXIMUM_WAITERS)
                {
                    // This can still overflow, but maybe there will never be that many waiters
                    turn = (Interlocked.Add(ref _owner, 2) & WAITERS_MASK) >> 1;
                }
            }

            // lock acquired failed and waiters updated

            //*** Step 2, Spinning and Yielding
            var spinner = new SpinWait();

            if (turn > PlatformHelper.ProcessorCount)
            {
                spinner.Count = SpinWait.YieldThreshold;
            }
            while (true)
            {
                spinner.SpinOnce(SLEEP_ONE_FREQUENCY);

                observedOwner = _owner;
                if ((observedOwner & LOCK_ANONYMOUS_OWNED) == LOCK_UNOWNED)
                {
                    int newOwner = (observedOwner & WAITERS_MASK) == 0 ? // Gets the number of waiters, if zero
                                   observedOwner | 1                     // don't decrement it. just set the lock bit, it is zero because a previous call of Exit(false) which corrupted the waiters
                           : (observedOwner - 2) | 1;                    // otherwise decrement the waiters and set the lock bit
                    Debug.Assert((newOwner & WAITERS_MASK) >= 0);

                    if (CompareExchange(ref _owner, newOwner, observedOwner, ref lockTaken) == observedOwner)
                    {
                        return;
                    }
                }

                if (spinner.Count % TIMEOUT_CHECK_FREQUENCY == 0)
                {
                    // Check the timeout.
                    if (millisecondsTimeout != Timeout.Infinite && TimeoutHelper.UpdateTimeOut(startTime, millisecondsTimeout) <= 0)
                    {
                        DecrementWaiters();
                        return;
                    }
                }
            }
        }
예제 #50
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();
                    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 unregister the token outside of the lock, to avoid deadlocks.
                using (cancellationToken.InternalRegisterWithoutEC(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 (!Monitor.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 unregisters) the callback

            return(true); //done. The wait was satisfied.
        }
예제 #51
0
        public bool Wait(int millisecondsTimeout, CancellationToken cancellationToken)
        {
            CheckState();
            if (millisecondsTimeout < -1)
            {
                throw new ArgumentOutOfRangeException("millisecondsTimeout",
                                                      "millisecondsTimeout is a negative number other than -1");
            }

            Stopwatch sw = Stopwatch.StartNew();

            Func <bool> stopCondition = () => millisecondsTimeout >= 0 && sw.ElapsedMilliseconds > millisecondsTimeout;

            do
            {
                bool shouldWait;
                int  result;

                do
                {
                    cancellationToken.ThrowIfCancellationRequested();
                    if (stopCondition())
                    {
                        return(false);
                    }

                    shouldWait = true;
                    result     = currCount;

                    if (result > 0)
                    {
                        shouldWait = false;
                    }
                    else
                    {
                        break;
                    }
                } while (Interlocked.CompareExchange(ref currCount, result - 1, result) != result);

                if (!shouldWait)
                {
                    if (result == 1)
                    {
                        handle.Reset();
                    }
                    break;
                }

                SpinWait wait = new SpinWait();

                while (Thread.VolatileRead(ref currCount) <= 0)
                {
                    cancellationToken.ThrowIfCancellationRequested();
                    if (stopCondition())
                    {
                        return(false);
                    }

                    if (wait.Count > spinCount)
                    {
                        int diff = millisecondsTimeout - (int)sw.ElapsedMilliseconds;

                        int timeout = millisecondsTimeout < 0 ? deepSleepTime :


                                      Math.Min(Math.Max(diff, 1), deepSleepTime);
                        handle.WaitOne(timeout);
                    }
                    else
                    {
                        wait.SpinOnce();
                    }
                }
            } while (true);

            return(true);
        }
예제 #52
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, SR.SemaphoreSlim_Wait_TimeoutWrong);
            }

            cancellationToken.ThrowIfCancellationRequested();

            // Perf: Check the stack timeout parameter before checking the volatile count
            if (millisecondsTimeout == 0 && m_currentCount == 0)
            {
                // Pessimistic fail fast, check volatile count outside lock (only when timeout is zero!)
                return(false);
            }

            uint startTime = 0;

            if (millisecondsTimeout != Timeout.Infinite && millisecondsTimeout > 0)
            {
                startTime = TimeoutHelper.GetTime();
            }

            bool        waitSuccessful = false;
            Task <bool> asyncWaitTask  = null;
            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.InternalRegisterWithoutEC(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 Monitor.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
                {
                    m_lock.Acquire();
                    lockTaken = true;
                    if (lockTaken)
                    {
                        m_waitCount++;
                    }
                }

                // If there are any async waiters, for fairness we'll get in line behind
                // then by translating our synchronous wait into an asynchronous one that we
                // then block on (once we've released the lock).
                if (m_asyncHead != null)
                {
                    Debug.Assert(m_asyncTail != null, "tail should not be null if head isn't");
                    asyncWaitTask = WaitAsync(millisecondsTimeout, cancellationToken);
                }
                // There are no async waiters, so we can proceed with normal synchronous waiting.
                else
                {
                    // If the count > 0 we are good to move on.
                    // If not, then wait if we were given allowed some wait duration

                    OperationCanceledException oce = null;

                    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
                        try
                        {
                            waitSuccessful = WaitUntilCountOrTimeout(millisecondsTimeout, startTime, cancellationToken);
                        }
                        catch (OperationCanceledException e) { oce = e; }
                    }

                    // Now try to acquire.  We prioritize acquisition over cancellation/timeout so that we don't
                    // lose any counts when there are asynchronous waiters in the mix.  Asynchronous waiters
                    // defer to synchronous waiters in priority, which means that if it's possible an asynchronous
                    // waiter didn't get released because a synchronous waiter was present, we need to ensure
                    // that synchronous waiter succeeds so that they have a chance to release.
                    Debug.Assert(!waitSuccessful || m_currentCount > 0,
                                 "If the wait was successful, there should be count available.");
                    if (m_currentCount > 0)
                    {
                        waitSuccessful = true;
                        m_currentCount--;
                    }
                    else if (oce != null)
                    {
                        throw oce;
                    }

                    // 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--;
                    m_lock.Release();
                }

                // Unregister the cancellation callback.
                cancellationTokenRegistration.Dispose();
            }

            // If we had to fall back to asynchronous waiting, block on it
            // here now that we've released the lock, and return its
            // result when available.  Otherwise, this was a synchronous
            // wait, and whether we successfully acquired the semaphore is
            // stored in waitSuccessful.

            return((asyncWaitTask != null) ? asyncWaitTask.GetAwaiter().GetResult() : waitSuccessful);
        }
예제 #53
0
        public bool Wait(int millisecondsTimeout, CancellationToken cancellationToken)
        {
            CheckDispose();

            // Validate input
            if (millisecondsTimeout < -1)
            {
                throw new ArgumentOutOfRangeException(
                          nameof(millisecondsTimeout), millisecondsTimeout, SR.SemaphoreSlim_Wait_TimeoutWrong);
            }

            cancellationToken.ThrowIfCancellationRequested();

            // Perf: Check the stack timeout parameter before checking the volatile count
            if (millisecondsTimeout == 0 && m_currentCount == 0)
            {
                // Pessimistic fail fast, check volatile count outside lock (only when timeout is zero!)
                return(false);
            }

            uint startTime = 0;

            if (millisecondsTimeout != Timeout.Infinite && millisecondsTimeout > 0)
            {
                startTime = TimeoutHelper.GetTime();
            }

            bool        waitSuccessful = false;
            Task <bool>?asyncWaitTask  = null;
            bool        lockTaken      = false;

            // Register for cancellation outside of the main lock.
            // NOTE: Register/unregister inside the lock can deadlock as different lock acquisition orders could
            //      occur for (1)this.m_lockObjAndDisposed and (2)cts.internalLock
            CancellationTokenRegistration cancellationTokenRegistration = cancellationToken.UnsafeRegister(s_cancellationTokenCanceledEventHandler, this);

            try
            {
                // Perf: first spin wait for the count to be positive.
                // This additional amount of spinwaiting in addition
                // to Monitor.Enter()'s spinwaiting has shown measurable perf gains in test scenarios.
                if (m_currentCount == 0)
                {
                    // Monitor.Enter followed by Monitor.Wait is much more expensive than waiting on an event as it involves another
                    // spin, contention, etc. The usual number of spin iterations that would otherwise be used here is increased to
                    // lessen that extra expense of doing a proper wait.
                    int spinCount = SpinWait.SpinCountforSpinBeforeWait * 4;

                    SpinWait spinner = default;
                    while (spinner.Count < spinCount)
                    {
                        spinner.SpinOnce(sleep1Threshold: -1);

                        if (m_currentCount != 0)
                        {
                            break;
                        }
                    }
                }
                Monitor.Enter(m_lockObjAndDisposed, ref lockTaken);
                m_waitCount++;

                // If there are any async waiters, for fairness we'll get in line behind
                // then by translating our synchronous wait into an asynchronous one that we
                // then block on (once we've released the lock).
                if (m_asyncHead != null)
                {
                    Debug.Assert(m_asyncTail != null, "tail should not be null if head isn't");
                    asyncWaitTask = WaitAsync(millisecondsTimeout, cancellationToken);
                }
                // There are no async waiters, so we can proceed with normal synchronous waiting.
                else
                {
                    // If the count > 0 we are good to move on.
                    // If not, then wait if we were given allowed some wait duration

                    OperationCanceledException?oce = null;

                    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
                        try
                        {
                            waitSuccessful = WaitUntilCountOrTimeout(millisecondsTimeout, startTime, cancellationToken);
                        }
                        catch (OperationCanceledException e) { oce = e; }
                    }

                    // Now try to acquire.  We prioritize acquisition over cancellation/timeout so that we don't
                    // lose any counts when there are asynchronous waiters in the mix.  Asynchronous waiters
                    // defer to synchronous waiters in priority, which means that if it's possible an asynchronous
                    // waiter didn't get released because a synchronous waiter was present, we need to ensure
                    // that synchronous waiter succeeds so that they have a chance to release.
                    Debug.Assert(!waitSuccessful || m_currentCount > 0,
                                 "If the wait was successful, there should be count available.");
                    if (m_currentCount > 0)
                    {
                        waitSuccessful = true;
                        m_currentCount--;
                    }
                    else if (oce != null)
                    {
                        throw oce;
                    }

                    // 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_lockObjAndDisposed);
                }

                // Unregister the cancellation callback.
                cancellationTokenRegistration.Dispose();
            }

            // If we had to fall back to asynchronous waiting, block on it
            // here now that we've released the lock, and return its
            // result when available.  Otherwise, this was a synchronous
            // wait, and whether we successfully acquired the semaphore is
            // stored in waitSuccessful.

            return((asyncWaitTask != null) ? asyncWaitTask.GetAwaiter().GetResult() : waitSuccessful);
        }
        public bool Wait(int millisecondsTimeout, CancellationToken cancellationToken)
        {
            this.CheckDispose();
            if (millisecondsTimeout < -1)
            {
                throw new ArgumentOutOfRangeException("totalMilliSeconds", millisecondsTimeout, GetResourceString("SemaphoreSlim_Wait_TimeoutWrong"));
            }
            cancellationToken.ThrowIfCancellationRequested();
            long startTimeTicks = 0L;

            if ((millisecondsTimeout != -1) && (millisecondsTimeout > 0))
            {
                startTimeTicks = DateTime.UtcNow.Ticks;
            }
            bool lockTaken = false;
            CancellationTokenRegistration registration = cancellationToken.Register(s_cancellationTokenCanceledEventHandler, this);

            try
            {
                SpinWait wait = new SpinWait();
                while ((this.m_currentCount == 0) && !wait.NextSpinWillYield)
                {
                    wait.SpinOnce();
                }
                try
                {
                }
                finally
                {
                    Monitor.Enter(this.m_lockObj, ref lockTaken);
                    if (lockTaken)
                    {
                        this.m_waitCount++;
                    }
                }
                if (this.m_currentCount == 0)
                {
                    if (millisecondsTimeout == 0)
                    {
                        return(false);
                    }
                    if (!this.WaitUntilCountOrTimeout(millisecondsTimeout, startTimeTicks, cancellationToken))
                    {
                        return(false);
                    }
                }
                this.m_currentCount--;
                if ((this.m_waitHandle != null) && (this.m_currentCount == 0))
                {
                    this.m_waitHandle.Reset();
                }
            }
            finally
            {
                if (lockTaken)
                {
                    this.m_waitCount--;
                    Monitor.Exit(this.m_lockObj);
                }
                registration.Dispose();
            }
            return(true);
        }
예제 #55
0
        public bool Wait(int millisecondsTimeout, CancellationToken cancellationToken)
        {
            this.CheckDispose();
            if (millisecondsTimeout < -1)
            {
                throw new ArgumentOutOfRangeException("totalMilliSeconds", millisecondsTimeout, SemaphoreSlim.GetResourceString("SemaphoreSlim_Wait_TimeoutWrong"));
            }
            cancellationToken.ThrowIfCancellationRequested();
            uint startTime = 0U;

            if (millisecondsTimeout != -1 && millisecondsTimeout > 0)
            {
                startTime = TimeoutHelper.GetTime();
            }
            bool        result = false;
            Task <bool> task   = null;
            bool        flag   = false;
            CancellationTokenRegistration cancellationTokenRegistration = cancellationToken.InternalRegisterWithoutEC(SemaphoreSlim.s_cancellationTokenCanceledEventHandler, this);

            try
            {
                SpinWait spinWait = default(SpinWait);
                while (this.m_currentCount == 0 && !spinWait.NextSpinWillYield)
                {
                    spinWait.SpinOnce();
                }
                try
                {
                }
                finally
                {
                    Monitor.Enter(this.m_lockObj, ref flag);
                    if (flag)
                    {
                        this.m_waitCount++;
                    }
                }
                if (this.m_asyncHead != null)
                {
                    task = this.WaitAsync(millisecondsTimeout, cancellationToken);
                }
                else
                {
                    OperationCanceledException ex = null;
                    if (this.m_currentCount == 0)
                    {
                        if (millisecondsTimeout == 0)
                        {
                            return(false);
                        }
                        try
                        {
                            result = this.WaitUntilCountOrTimeout(millisecondsTimeout, startTime, cancellationToken);
                        }
                        catch (OperationCanceledException ex2)
                        {
                            ex = ex2;
                        }
                    }
                    if (this.m_currentCount > 0)
                    {
                        result = true;
                        this.m_currentCount--;
                    }
                    else if (ex != null)
                    {
                        throw ex;
                    }
                    if (this.m_waitHandle != null && this.m_currentCount == 0)
                    {
                        this.m_waitHandle.Reset();
                    }
                }
            }
            finally
            {
                if (flag)
                {
                    this.m_waitCount--;
                    Monitor.Exit(this.m_lockObj);
                }
                cancellationTokenRegistration.Dispose();
            }
            if (task == null)
            {
                return(result);
            }
            return(task.GetAwaiter().GetResult());
        }
예제 #56
0
        public bool SignalAndWait(int millisecondsTimeout, CancellationToken cancellationToken)
        {
            bool flag;
            int  num;
            int  num2;
            int  currentTotalCount;

            this.ThrowIfDisposed();
            cancellationToken.ThrowIfCancellationRequested();
            if (millisecondsTimeout < -1)
            {
                throw new ArgumentOutOfRangeException("millisecondsTimeout", millisecondsTimeout, SR.GetString("Barrier_SignalAndWait_ArgumentOutOfRange"));
            }
            if ((this.m_actionCallerID != 0) && (Thread.CurrentThread.ManagedThreadId == this.m_actionCallerID))
            {
                throw new InvalidOperationException(SR.GetString("Barrier_InvalidOperation_CalledFromPHA"));
            }
            SpinWait wait = new SpinWait();

            while (true)
            {
                currentTotalCount = this.m_currentTotalCount;
                this.GetCurrentTotal(currentTotalCount, out num2, out num, out flag);
                if (num == 0)
                {
                    throw new InvalidOperationException(SR.GetString("Barrier_SignalAndWait_InvalidOperation_ZeroTotal"));
                }
                if ((num2 == 0) && (flag != ((this.m_currentPhase % 2L) == 0L)))
                {
                    throw new InvalidOperationException(SR.GetString("Barrier_SignalAndWait_InvalidOperation_ThreadsExceeded"));
                }
                if ((num2 + 1) == num)
                {
                    if (this.SetCurrentTotal(currentTotalCount, 0, num, !flag))
                    {
                        if (CdsSyncEtwBCLProvider.Log.IsEnabled())
                        {
                            CdsSyncEtwBCLProvider.Log.Barrier_PhaseFinished(flag, this.m_currentPhase);
                        }
                        this.FinishPhase(flag);
                        return(true);
                    }
                }
                else if (this.SetCurrentTotal(currentTotalCount, num2 + 1, num, flag))
                {
                    break;
                }
                wait.SpinOnce();
            }
            long currentPhase         = this.m_currentPhase;
            ManualResetEventSlim slim = flag ? this.m_evenEvent : this.m_oddEvent;
            bool flag2 = false;
            bool flag3 = false;

            try
            {
                flag3 = slim.Wait(millisecondsTimeout, cancellationToken);
            }
            catch (OperationCanceledException)
            {
                flag2 = true;
            }
            if (!flag3)
            {
                wait.Reset();
                while (true)
                {
                    bool flag4;
                    currentTotalCount = this.m_currentTotalCount;
                    this.GetCurrentTotal(currentTotalCount, out num2, out num, out flag4);
                    if ((currentPhase != this.m_currentPhase) || (flag != flag4))
                    {
                        slim.Wait();
                        break;
                    }
                    if (this.SetCurrentTotal(currentTotalCount, num2 - 1, num, flag))
                    {
                        if (flag2)
                        {
                            throw new OperationCanceledException(SR.GetString("Common_OperationCanceled"), cancellationToken);
                        }
                        return(false);
                    }
                    wait.SpinOnce();
                }
            }
            if (this.m_exception != null)
            {
                throw new BarrierPostPhaseException(this.m_exception);
            }
            return(true);
        }
        /// <summary>
        /// Signals that a participant has reached the barrier and waits for all other participants to reach
        /// the barrier as well, using a
        /// 32-bit signed integer to measure the time interval, while observing a <see
        /// cref="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="System.Threading.CancellationToken"/> to
        /// observe.</param>
        /// <returns>true if all other participants reached the barrier; otherwise, false.</returns>
        /// <exception cref="System.ArgumentOutOfRangeException"><paramref name="millisecondsTimeout"/> is a
        /// negative number other than -1, which represents an infinite time-out.</exception>
        /// <exception cref="System.InvalidOperationException">
        /// The method was invoked from within a post-phase action, the barrier currently has 0 participants,
        /// or the barrier is being used by more threads than are registered as participants.
        /// </exception>
        /// <exception cref="System.OperationCanceledException"><paramref name="cancellationToken"/> has been
        /// canceled.</exception>
        /// <exception cref="System.ObjectDisposedException">The current instance has already been
        /// disposed.</exception>
        public bool SignalAndWait(int millisecondsTimeout, CancellationToken cancellationToken)
        {
            ThrowIfDisposed();
            cancellationToken.ThrowIfCancellationRequested();

            if (millisecondsTimeout < -1)
            {
                throw new System.ArgumentOutOfRangeException(nameof(millisecondsTimeout), millisecondsTimeout,
                                                             SR.Barrier_SignalAndWait_ArgumentOutOfRange);
            }

            // in case of this is called from the PHA
            if (_actionCallerID != 0 && Environment.CurrentManagedThreadId == _actionCallerID)
            {
                throw new InvalidOperationException(SR.Barrier_InvalidOperation_CalledFromPHA);
            }

            // local variables to extract the basic barrier variable and update them
            // The are declared here instead of inside the loop body because the will be used outside the loop
            bool     sense; // The sense of the barrier *before* the phase associated with this SignalAndWait call completes
            int      total;
            int      current;
            int      currentTotal;
            long     phase;
            SpinWait spinner = default;

            while (true)
            {
                currentTotal = _currentTotalCount;
                GetCurrentTotal(currentTotal, out current, out total, out sense);
                phase = CurrentPhaseNumber;
                // throw if zero participants
                if (total == 0)
                {
                    throw new InvalidOperationException(SR.Barrier_SignalAndWait_InvalidOperation_ZeroTotal);
                }
                // Try to detect if the number of threads for this phase exceeded the total number of participants or not
                // This can be detected if the current is zero which means all participants for that phase has arrived and the phase number is not changed yet
                if (current == 0 && sense != (CurrentPhaseNumber % 2 == 0))
                {
                    throw new InvalidOperationException(SR.Barrier_SignalAndWait_InvalidOperation_ThreadsExceeded);
                }
                //This is the last thread, finish the phase
                if (current + 1 == total)
                {
                    if (SetCurrentTotal(currentTotal, 0, total, !sense))
                    {
                        if (CdsSyncEtwBCLProvider.Log.IsEnabled())
                        {
                            CdsSyncEtwBCLProvider.Log.Barrier_PhaseFinished(sense, CurrentPhaseNumber);
                        }
                        FinishPhase(sense);
                        return(true);
                    }
                }
                else if (SetCurrentTotal(currentTotal, current + 1, total, sense))
                {
                    break;
                }

                spinner.SpinOnce(sleep1Threshold: -1);
            }

            // ** Perform the real wait **
            // select the correct event to wait on, based on the current sense.
            ManualResetEventSlim eventToWaitOn = (sense) ? _evenEvent : _oddEvent;

            bool waitWasCanceled = false;
            bool waitResult      = false;

            try
            {
                waitResult = DiscontinuousWait(eventToWaitOn, millisecondsTimeout, cancellationToken, phase);
            }
            catch (OperationCanceledException)
            {
                waitWasCanceled = true;
            }
            catch (ObjectDisposedException)// in case a race happen where one of the thread returned from SignalAndWait and the current thread calls Wait on a disposed event
            {
                // make sure the current phase for this thread is already finished, otherwise propagate the exception
                if (phase < CurrentPhaseNumber)
                {
                    waitResult = true;
                }
                else
                {
                    throw;
                }
            }



            if (!waitResult)
            {
                //reset the spinLock to prepare it for the next loop
                spinner.Reset();

                //If the wait timeout expired and all other thread didn't reach the barrier yet, update the current count back
                while (true)
                {
                    bool newSense;
                    currentTotal = _currentTotalCount;
                    GetCurrentTotal(currentTotal, out current, out total, out newSense);
                    // If the timeout expired and the phase has just finished, return true and this is considered as succeeded SignalAndWait
                    //otherwise the timeout expired and the current phase has not been finished yet, return false
                    //The phase is finished if the phase member variable is changed (incremented) or the sense has been changed
                    // we have to use the statements in the comparison below for two cases:
                    // 1- The sense is changed but the last thread didn't update the phase yet
                    // 2- The phase is already incremented but the sense flipped twice due to the termination of the next phase
                    if (phase < CurrentPhaseNumber || sense != newSense)
                    {
                        // The current phase has been finished, but we shouldn't return before the events are set/reset otherwise this thread could start
                        // next phase and the appropriate event has not reset yet which could make it return immediately from the next phase SignalAndWait
                        // before waiting other threads
                        WaitCurrentPhase(eventToWaitOn, phase);
                        Debug.Assert(phase < CurrentPhaseNumber);
                        break;
                    }
                    //The phase has not been finished yet, try to update the current count.
                    if (SetCurrentTotal(currentTotal, current - 1, total, sense))
                    {
                        //if here, then the attempt to back out was successful.
                        //throw (a fresh) OCE if cancellation woke the wait
                        //or return false if it was the timeout that woke the wait.
                        //
                        if (waitWasCanceled)
                        {
                            throw new OperationCanceledException(SR.Common_OperationCanceled, cancellationToken);
                        }
                        else
                        {
                            return(false);
                        }
                    }
                    spinner.SpinOnce(sleep1Threshold: -1);
                }
            }

            if (_exception != null)
            {
                throw new BarrierPostPhaseException(_exception);
            }

            return(true);
        }