//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;
                }
            }
        }
示例#2
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);
			});
		}
示例#3
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;
            }
        }
示例#4
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();
        }
        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();
        }
示例#6
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);
     }
 }
示例#7
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();
                    }
                }
            }
        }
        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);
        }
		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());
            }
        }
示例#11
0
        public bool EnterWriteLock(bool block)
        {
            var start = HiResTimer.Now();
#if DEBUG
            if (m_lastWriteThreadID == Thread.CurrentThread.ManagedThreadId)
                throw new SynchronizationLockException("Write lock already owned by you");
#endif

            var sw = new SpinWait();
            do
            {
                // If there are no readers or writers, grab the write lock.
                var state = m_state;
                if (state == 0 &&
                    Interlocked.CompareExchange(ref m_state, MASK_WRITER_BIT, state) == state)
                {
#if DEBUG
                    m_lastWriteThreadID = Thread.CurrentThread.ManagedThreadId;
                    if (sw.Count > _spinThreshold)
                        Debug.Print("EnterWriteLock: {0} spins ({1:F1}ms)", sw.Count, HiResTimer.ToTimeSpan(HiResTimer.Now() - start).TotalMilliseconds);
#endif
#if DEBUG_ReaderWriterSpinLock
                    if (ID != 0)
                        Debug.Print("{0} Enter Write on #{1} ({2})", Thread.CurrentThread.ManagedThreadId, ID, m_lastWriteThreadID);
#endif

                    return true;
                }

                sw.SpinOnce();
            }
            while (block);
            return false;
        }
示例#12
0
        public static void RunSpinWaitTests()
        {
            SpinWait spinner = new SpinWait();

            spinner.SpinOnce();
            Assert.Equal(spinner.Count, 1);
        }
示例#13
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");
                }
            }
        }
示例#14
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);
    }
示例#15
0
		public SpinLock (bool trackId)
		{
			this.isThreadOwnerTrackingEnabled = trackId;
			this.threadWhoTookLock = 0;
			this.lockState = isFree;
			this.sw = new SpinWait();
		}
        /// <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;
        }
示例#17
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;
        }
 public void StartNext(CompletionLink next) {
    var spinner = new SpinWait();
    while (!current._RestartWith(next)) {
       spinner.SpinOnce();
    }
    next._Start();
    current = next;
 }
        public void EnterWriteLock()
        {
            var w = new SpinWait();

            while (0 != Interlocked.CompareExchange(ref _lock, _writerLock, 0))
            {
                w.SpinOnce();
            }
        }
示例#20
0
        public void Wait()
        {
            SpinWait wait = new SpinWait();

            wait.SpinOnce();

            while (Count > 0)
                Thread.Sleep(1);
        }
示例#21
0
		protected void WaitForStatus()
		{
			if (GetIsCompleted())
				return;

			SpinWait wait = new SpinWait();
			while (!GetIsCompleted())
				wait.SpinOnce();
		}
        /// <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();
            }
        }
示例#23
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);
            }
        }
 public long AddParticipants(int participantCount)
 {
     this.ThrowIfDisposed();
     if (participantCount < 1)
     {
         throw new ArgumentOutOfRangeException("participantCount", participantCount, SR.GetString("Barrier_AddParticipants_NonPositive_ArgumentOutOfRange"));
     }
     if (participantCount > 0x7fff)
     {
         throw new ArgumentOutOfRangeException("participantCount", SR.GetString("Barrier_AddParticipants_Overflow_ArgumentOutOfRange"));
     }
     if ((this.m_actionCallerID != 0) && (Thread.CurrentThread.ManagedThreadId == this.m_actionCallerID))
     {
         throw new InvalidOperationException(SR.GetString("Barrier_InvalidOperation_CalledFromPHA"));
     }
     SpinWait wait = new SpinWait();
     long num = 0L;
     while (true)
     {
         int num3;
         int num4;
         bool flag;
         int currentTotalCount = this.m_currentTotalCount;
         this.GetCurrentTotal(currentTotalCount, out num4, out num3, out flag);
         if ((participantCount + num3) > 0x7fff)
         {
             throw new ArgumentOutOfRangeException("participantCount", SR.GetString("Barrier_AddParticipants_Overflow_ArgumentOutOfRange"));
         }
         if (this.SetCurrentTotal(currentTotalCount, num4, num3 + participantCount, flag))
         {
             long currentPhase = this.m_currentPhase;
             num = (flag != ((currentPhase % 2L) == 0L)) ? (currentPhase + 1L) : currentPhase;
             if (num != currentPhase)
             {
                 if (flag)
                 {
                     this.m_oddEvent.Wait();
                     return num;
                 }
                 this.m_evenEvent.Wait();
                 return num;
             }
             if (flag && this.m_evenEvent.IsSet)
             {
                 this.m_evenEvent.Reset();
                 return num;
             }
             if (!flag && this.m_oddEvent.IsSet)
             {
                 this.m_oddEvent.Reset();
             }
             return num;
         }
         wait.SpinOnce();
     }
 }
示例#25
0
        public void Spin(int x)
        {
            Benchmark.Iterate(() => 
            {
                for (var spin = new SpinWait(); spin.Count < x; spin.SpinOnce())
                {

                }
            });
        }
示例#26
0
 private void UpdateStateAtomically(int newBits, int updateBitsMask) {
     SpinWait sw = new SpinWait();
     do {
         int state = m_combinedState;
         int newState = (state & ~updateBitsMask) | newBits;
         if (Interlocked.CompareExchange(ref m_combinedState, newState, state) == state)
             return;
         sw.SpinOnce();
     } while (true);
 }
示例#27
0
        private void EndlessLoop(CancellationToken token)
        {
            var wait = new System.Threading.SpinWait();

            while (!token.IsCancellationRequested)
            {
                //do smth
                wait.SpinOnce(100);
            }
        }
 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;
     }
 }
        /// <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);
        }
示例#30
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);
 }
示例#32
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);
	}
示例#33
0
        private void run(CancellationToken token)
        {
            using (var gateway = _gatewayFactory())
            {
                var spin = new SpinWait();

                try
                {
                    Log.DebugFormat("[RequestProcessor] Entering mainloop. Thread Id: {0}",
                        Thread.CurrentThread.ManagedThreadId);

                    while (token.IsCancellationRequested == false)
                    {
                        bool processed = gateway.ProcessResponse();

                        PendingResRequest pendingResRequest;

                        while (_buffer.TryDequeue(out pendingResRequest))
                        {
                            if (pendingResRequest.ShouldDrop())
                            {
                                pendingResRequest.Drop();
                                continue;
                            }

                            gateway.SendRequest(pendingResRequest);
                            processed = true;
                            break;
                        }

                        if (!processed)
                            spin.SpinOnce();
                    }

                    Log.DebugFormat("[RequestProcessor] Exiting mainloop. Thread ID: {0}",
                        Thread.CurrentThread.ManagedThreadId);
                }
                catch (Exception e)
                {
                    Log.DebugFormat("[RequestProcessor] Error in mainloop. Thread ID: {0}", e,
                        Thread.CurrentThread.ManagedThreadId);
                }
                finally
                {
                    Log.DebugFormat("[RequestProcessor] Shutting down gateway. Thread ID: {0}",
                        Thread.CurrentThread.ManagedThreadId);
                    gateway.Dispose();
                    Log.DebugFormat("[RequestProcessor] Gateway shutdown. Thread ID: {0}",
                        Thread.CurrentThread.ManagedThreadId);
                }
            }
        }
示例#34
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;
        }
示例#35
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;
		}
示例#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);
            }
        }
        // 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 (NET_4_6 && UNITY_2017)
            System.Threading.SpinWait spin = new System.Threading.SpinWait();
#else
            Core.Utils.SpinWait spin = new Core.Utils.SpinWait();
#endif
            while (Interlocked.Increment(ref _freeNumber) != 1)
            {
                Interlocked.Decrement(ref _freeNumber);
                spin.SpinOnce();
            }
            if (_pool.Count > _pool.Capacity - 5)
            {
                _old  = _pool;
                _pool = new RingBuffer <object>(_old.Capacity * 2);
                _logger.InfoFormat("ring buffer not big enough for object pool of type {0}",
                                   _factory.MakeObject().GetType());
                if (_old.Count > 0)
                {
                    object obj;
                    var    succ = _old.TryDequeue(out obj);
                    while (succ && obj != null)
                    {
                        _pool.Enqueue(obj);
                        succ = _old.TryDequeue(out obj);
                    }
                }
                _old = null;
            }



            {
                _pool.Enqueue(t);
                Interlocked.Decrement(ref _freeNumber);
            }
        }
示例#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
        /// <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);
        }
示例#40
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.");
        }
示例#41
0
文件: SpinLock.cs 项目: rivy/corert
        /// <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 ir 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 System.ArgumentException(SR.SpinLock_TryReliableEnter_ArgumentException);
            }

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


            uint startTime = 0;

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

            if (CdsSyncEtwBCLProvider.Log.IsEnabled())
            {
                CdsSyncEtwBCLProvider.Log.SpinLock_FastPathFailed(m_owner);
            }

            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 avilability
            // 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 = m_owner;
            if ((observedOwner & LOCK_ANONYMOUS_OWNED) == LOCK_UNOWNED)
            {
                if (CompareExchange(ref m_owner, observedOwner | 1, observedOwner, ref lockTaken) == observedOwner)
                {
                    return;
                }
            }
            else //failed to acquire the lock,then try to update the waiters. If the waiters count reached the maximum, jsut break the loop to avoid overflow
            {
                if ((observedOwner & WAITERS_MASK) != MAXIMUM_WAITERS)
                {
                    turn = (Interlocked.Add(ref m_owner, 2) & WAITERS_MASK) >> 1;
                }
            }



            // Check the timeout.
            if (millisecondsTimeout == 0 ||
                (millisecondsTimeout != Timeout.Infinite &&
                 TimeoutHelper.UpdateTimeOut(startTime, millisecondsTimeout) <= 0))
            {
                DecrementWaiters();
                return;
            }

            //***Step 2. Spinning
            //lock acquired failed and waiters updated
            int processorCount = PlatformHelper.ProcessorCount;

            if (turn < processorCount)
            {
                int processFactor = 1;
                for (int i = 1; i <= turn * SPINNING_FACTOR; i++)
                {
                    SpinWait.Spin((turn + i) * SPINNING_FACTOR * processFactor);
                    if (processFactor < processorCount)
                    {
                        processFactor++;
                    }
                    observedOwner = m_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 zzero because a previous call of Exit(false) ehich corrupted the waiters
                            : (observedOwner - 2) | 1;                       // otherwise decrement the waiters and set the lock bit
                        Contract.Assert((newOwner & WAITERS_MASK) >= 0);

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

            // Check the timeout.
            if (millisecondsTimeout != Timeout.Infinite && TimeoutHelper.UpdateTimeOut(startTime, millisecondsTimeout) <= 0)
            {
                DecrementWaiters();
                return;
            }

            //*** Step 3, Yielding
            //Sleep(1) every 50 yields
            int yieldsoFar = 0;

            while (true)
            {
                observedOwner = m_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 zzero because a previous call of Exit(false) ehich corrupted the waiters
                           : (observedOwner - 2) | 1;                    // otherwise decrement the waiters and set the lock bit
                    Contract.Assert((newOwner & WAITERS_MASK) >= 0);

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

                if (yieldsoFar % SLEEP_ONE_FREQUENCY == 0)
                {
                    Helpers.Sleep(1);
                }
                else if (yieldsoFar % SLEEP_ZERO_FREQUENCY == 0)
                {
                    Helpers.Sleep(0);
                }
                else
                {
                    SpinWait.Yield();
                }

                if (yieldsoFar % TIMEOUT_CHECK_FREQUENCY == 0)
                {
                    //Check the timeout.
                    if (millisecondsTimeout != Timeout.Infinite && TimeoutHelper.UpdateTimeOut(startTime, millisecondsTimeout) <= 0)
                    {
                        DecrementWaiters();
                        return;
                    }
                }

                yieldsoFar++;
            }
        }
示例#42
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();
            }
        }
示例#43
0
        public void Set()
        {
            var spinWait = new SpinWait();

            while (true)
            {
                var status = (Status)Volatile.Read(ref _status);
                switch (status)
                {
                case Status.Disposed:
                    // Disposed
                    // Fail saliently
                    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.HandleRequestedNotSet:
                    // 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);
                    switch (status)
                    {
                    case Status.HandleReadyNotSet:
                    {
                        // We set it
                        // Update the wait handle
                        var handle = Volatile.Read(ref _handle);
                        if (handle != null)
                        {
                            // Reset it
                            handle.Set();
                            // Done
                            return;
                        }

                        break;
                    }

                    case Status.HandleReadySet:
                        // Another thread set it
                        // we are done
                        return;

                    default:
                        break;
                    }

                    // Probably Disposed
                    break;

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

                default:
                    // Should not happen
                    break;
                }

                spinWait.SpinOnce();
            }
        }
示例#44
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;
            }
        }
示例#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>
        /// 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(
                          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/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);
        }
示例#47
0
        public bool Wait(int millisecondsTimeout, CancellationToken cancellationToken)
        {
            CheckState();
            if (millisecondsTimeout < -1)
            {
                throw new ArgumentOutOfRangeException("millisecondsTimeout",
                                                      "millisecondsTimeout is a negative number other than -1");
            }

            Watch sw = Watch.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)
                    {
                        handle.WaitOne(Math.Min(Math.Max(millisecondsTimeout - (int)sw.ElapsedMilliseconds, 1), deepSleepTime));
                    }
                    else
                    {
                        wait.SpinOnce();
                    }
                }
            } while (true);

            return(true);
        }
示例#48
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.Sleep1ThresholdForLongSpinBeforeWait);

                    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.
        }
示例#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>
        /// 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(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  = new SpinWait();
            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 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
                    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 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);
        }
示例#51
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 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 = new SpinWait();

            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();
            }

            // ** 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 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 OperationCanceledException(SR.Common_OperationCanceled, cancellationToken);
                        }
                        else
                        {
                            return(false);
                        }
                    }
                    spinner.SpinOnce();
                }
            }

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

            return(true);
        }
示例#52
0
 private void WriteToFile(ref System.Threading.SpinWait spinWait)
 {
     File.AppendAllText(_fileName, $"{nameof(SpinWait)}: {DateTime.Now:hh:mm:ss:ffff} {Environment.NewLine}");
 }
示例#53
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);
        }
示例#54
0
        public bool Wait(int millisecondsTimeout, CancellationToken cancellationToken)
        {
            CheckDispose();

            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 is not null)
                {
                    Debug.Assert(m_asyncTail is not 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 is not null)
                    {
                        throw oce;
                    }

                    // Exposing wait handle which is lazily initialized if needed
                    if (m_waitHandle is not 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 is not null) ? asyncWaitTask.GetAwaiter().GetResult() : waitSuccessful);
        }