public void ParticipateUntil (Func<bool> predicate) { SpinWait sw = new SpinWait (); while (!predicate ()) sw.SpinOnce (); }
public static void Run() { var queue = new ConcurrentQueue<int>(); // begin var producer = Task.Run(() => { foreach (var value in Enumerable.Range(1, 10000)) { queue.Enqueue(value); } }); var consumer = Task.Run(() => { var spinWait = new SpinWait(); var value = 0; while (value != 10000) { if (!queue.TryDequeue(out value)) { spinWait.SpinOnce(); continue; } Logger.Log("Value: {0}", value); } }); Task.WaitAll(producer, consumer); // end }
public static void RunSpinWaitTests() { SpinWait spinner = new SpinWait(); spinner.SpinOnce(); Assert.Equal(spinner.Count, 1); }
internal bool SlowEnter (StCancelArgs cargs) { int lastTime = (cargs.Timeout != Timeout.Infinite) ? Environment.TickCount : 0; StWaitBlock wb = null; do { int sc = spinCount; #if NET_4_0 var spinWait = new SpinWait (); #endif do { if (state == FREE && Interlocked.CompareExchange (ref state, BUSY, FREE) == FREE) { return true; } if (top != null || sc-- <= 0) { break; } #if NET_4_0 spinWait.SpinOnce (); #else Thread.SpinWait (1); #endif } while (true); if (wb == null) { wb = new StWaitBlock (1); } else { wb.parker.Reset (); } do { StWaitBlock t; wb.next = t = top; if (Interlocked.CompareExchange (ref top, wb, t) == t) { break; } } while (true); if (TryEnter ()) { wb.parker.SelfCancel (); return true; } int ws = wb.parker.Park (cargs); if (ws != StParkStatus.Success) { cargs.ThrowIfException (ws); return false; } if (TryEnter ()) { return true; } if (!cargs.AdjustTimeout (ref lastTime)) { return false; } } while (true); }
public void Enter() { // If calling thread already owns the lock, increment recursion count and return Int32 threadId = Thread.CurrentThread.ManagedThreadId; if (threadId == m_owningThreadId) { m_recursion++; return; } // The calling thread doesn't own the lock, try to get it SpinWait spinwait = new SpinWait(); for (Int32 spinCount = 0; spinCount < m_spincount; spinCount++) { // If the lock was free, this thread got it; set some state and return if (Interlocked.CompareExchange(ref m_waiters, 1, 0) == 0) goto GotLock; // Black magic: give other threads a chance to run // in hopes that the lock will be released spinwait.SpinOnce(); } // Spinning is over and the lock was still not obtained, try one more time if (Interlocked.Increment(ref m_waiters) > 1) { // Still contention, this thread must wait m_waiterLock.WaitOne(); // Wait for the lock; performance hit // When this thread wakes, it owns the lock; set some state and return } GotLock: // When a thread gets the lock, we record its ID and // indicate that the thread owns the lock once m_owningThreadId = threadId; m_recursion = 1; }
public void ParallelForTestCase () { ParallelTestHelper.Repeat (() => { int[] expected = Enumerable.Range (1, 1000).Select ((e) => e * 2).ToArray (); int[] actual = Enumerable.Range (1, 1000).ToArray (); SpinWait sw = new SpinWait (); Parallel.For (0, actual.Length, (i) => { actual[i] *= 2; sw.SpinOnce (); }); CollectionAssert.AreEquivalent (expected, actual, "#1, same"); CollectionAssert.AreEqual (expected, actual, "#2, in order"); }); }
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; }
public void EnterReadLock() { SpinWait sw = new SpinWait(); do { while ((rwlock & (RwWrite | RwWait)) > 0) sw.SpinOnce(); if ((Interlocked.Add(ref rwlock, RwRead) & (RwWait | RwWait)) == 0) return; Interlocked.Add(ref rwlock, -RwRead); } while (true); }
/// <summary> /// 循环工作 /// </summary> private static void LoopWork() { var spinWait = new SpinWait(); while (true) { lock (syncRoot) { foreach (var item in actions) { item.Invoke(); } } spinWait.SpinOnce(); } }
public override Event Dequeue() { Event result = null; SpinWait spinWait = new SpinWait(); while (!closing) { if (queue.TryDequeue(out result)) { break; } spinWait.SpinOnce(); } return result; }
public static int SendWithTimeout(this ZmqSocket socket, byte[] buffer, int length, TimeSpan timeout) { var stopwatch = Stopwatch.StartNew(); var spinWait = new SpinWait(); int result; do { result = socket.Send(buffer, length, SocketFlags.DontWait); if (socket.SendStatus != SendStatus.TryAgain) break; spinWait.SpinOnce(); } while (stopwatch.Elapsed <= timeout); return result; }
public static bool SpinWaitForCondition(Func<bool> predicate, int timeout) { Thread.MemoryBarrier(); var sw = new Stopwatch(); var spin = new SpinWait(); sw.Start(); while (sw.ElapsedMilliseconds < timeout) { if (predicate()) { sw.Stop(); return true; } spin.SpinOnce(); } sw.Stop(); return false; }
protected override void ConsumeItems( int count ) { SpinWait spinWait = new SpinWait(); int value; for ( int i = 0; i < count; ) { if ( this.queue.TryDequeue( out value ) ) { i++; spinWait.Reset(); } else { spinWait.SpinOnce(); } } }
public void EnterWriteLock() { SpinWait sw = new SpinWait(); do { int state = rwlock; if (state < RwWrite) { if (Interlocked.CompareExchange(ref rwlock, RwWrite, state) == state) return; state = rwlock; } // We register our interest in taking the Write lock (if upgradeable it's already done) while ((state & RwWait) == 0 && Interlocked.CompareExchange(ref rwlock, state | RwWait, state) != state) state = rwlock; // Before falling to sleep while (rwlock > RwWait) sw.SpinOnce(); } while (true); }
public void EnterReadLock (ref bool taken) { if (taken) throw new ArgumentException ("taken", "taken needs to be set to false"); SpinWait sw = new SpinWait (); bool cont = true; do { while ((rwlock & (RwWrite | RwWait)) > 0) sw.SpinOnce (); try {} finally { if ((Interlocked.Add (ref rwlock, RwRead) & (RwWait | RwWait)) == 0) { taken = true; cont = false; } else { Interlocked.Add (ref rwlock, -RwRead); } } } while (cont); }
/// <summary> /// Exists the semaphore the specified number of times /// </summary> /// <param name="releaseCount">The number of times to exit the semaphore</param> public void Release(int releaseCount) { if (_isDisposed) { throw new ObjectDisposedException(this.GetType().Name); } if (releaseCount < 1) { throw new ArgumentOutOfRangeException(nameof(releaseCount), "releaseCount should be positive"); } if (_maxCount - CurrentCount < releaseCount) { throw new SemaphoreFullException(); } int waiterAndWaitCountDiff = 0; int releaseCountForWait = 0; int releaseCountLocFree = releaseCount; if (_waitCount > 0) { waiterAndWaitCountDiff = GetWaiterAndWaitCountDiffAtomic(); releaseCountForWait = Math.Min(releaseCount, waiterAndWaitCountDiff); // Приоритет waiter'ам releaseCountLocFree = releaseCount - releaseCountForWait; } TurboContract.Assert(releaseCountForWait >= 0, conditionString: "releaseCountForWait >= 0"); TurboContract.Assert(releaseCountLocFree >= 0, conditionString: "releaseCountLocFree >= 0"); TurboContract.Assert(releaseCountForWait + releaseCountLocFree == releaseCount, conditionString: "releaseCountForWait + releaseCountLocFree == releaseCount"); // Сначала возврат в lockFree if (releaseCountLocFree > 0) { int currentCountLocFree = Interlocked.Add(ref _currentCountLockFree, releaseCountLocFree); TurboContract.Assert(currentCountLocFree > 0, conditionString: "currentCountLocFree > 0"); } // Теперь возврат для waiter'ов. Если число waiter'ов увеличилось, то тоже нужно зайти в lock if (releaseCountForWait > 0 || (_waitCount > 0 && GetWaiterAndWaitCountDiffAtomic() > waiterAndWaitCountDiff)) { lock (_lockObj) { int waitCount = _waitCount; int currentCountForWait = _currentCountForWait; int nextCurrentCountForWait = currentCountForWait + releaseCountForWait; // В идеале _waitCount == _currentCountForWait. Если нет, то предпринимаем действия if (nextCurrentCountForWait > waitCount && releaseCountForWait > 0) { // Если слотов оказывается больше, то избыток возвращаем в _currentCountLocFree int countForReturnToLockFree = Math.Min(releaseCountForWait, nextCurrentCountForWait - waitCount); int currentCountLocFree = Interlocked.Add(ref _currentCountLockFree, countForReturnToLockFree); TurboContract.Assert(currentCountLocFree > 0, conditionString: "currentCountLocFree > 0"); releaseCountForWait -= countForReturnToLockFree; releaseCountLocFree += countForReturnToLockFree; } else if (nextCurrentCountForWait < waitCount) { // Если меньше, то пытаемся захватить себе обратно // Не можем забрать больше, чем было добавлено этим вызовом Release int maxToRequestFromLockFree = Math.Min(releaseCountLocFree, waitCount - nextCurrentCountForWait); if (maxToRequestFromLockFree > 0) { SpinWait spin = new SpinWait(); int currentCountLocFree = _currentCountLockFree; int countToRequestFromLockFree = Math.Min(currentCountLocFree, maxToRequestFromLockFree); while (countToRequestFromLockFree > 0) { TurboContract.Assert(currentCountLocFree - countToRequestFromLockFree >= 0, conditionString: "currentCountLocFree - countToRequestFromLockFree >= 0"); if (Interlocked.CompareExchange(ref _currentCountLockFree, currentCountLocFree - countToRequestFromLockFree, currentCountLocFree) == currentCountLocFree) { releaseCountForWait += countToRequestFromLockFree; releaseCountLocFree -= countToRequestFromLockFree; break; } spin.SpinOnce(); currentCountLocFree = _currentCountLockFree; countToRequestFromLockFree = Math.Min(currentCountLocFree, maxToRequestFromLockFree); } } } TurboContract.Assert(releaseCountForWait >= 0, conditionString: "releaseCountForWait >= 0"); TurboContract.Assert(releaseCountLocFree >= 0, conditionString: "releaseCountLocFree >= 0"); TurboContract.Assert(releaseCountForWait + releaseCountLocFree == releaseCount, conditionString: "releaseCountForWait + releaseCountLocFree == releaseCount"); if (releaseCountForWait > 0) { TurboContract.Assert(_currentCountForWait == currentCountForWait, conditionString: "_currentCountForWait == currentCountForWait"); currentCountForWait += releaseCountForWait; TurboContract.Assert(currentCountForWait > 0, conditionString: "currentCountForWait > 0"); int waitersToNotify = Math.Min(currentCountForWait, waitCount); for (int i = 0; i < waitersToNotify; i++) { Monitor.Pulse(_lockObj); } _currentCountForWait = currentCountForWait; } } } }
public void EnterWriteLock (ref bool taken) { if (taken) throw new ArgumentException ("taken", "taken needs to be set to false"); SpinWait sw = new SpinWait (); int state = rwlock; try { do { state = rwlock; if (state < RwWrite) { try {} finally { if (Interlocked.CompareExchange (ref rwlock, RwWrite, state) == state) taken = true; } if (taken) return; state = rwlock; } while ((state & RwWait) == 0 && Interlocked.CompareExchange (ref rwlock, state | RwWait, state) != state) state = rwlock; while (rwlock > RwWait) sw.SpinOnce (); } while (true); } finally { state = rwlock; if (!taken && (state & RwWait) != 0) Interlocked.CompareExchange (ref rwlock, state - RwWait, state); } }
private void RunUploadLoop( BlobTransferContext transferContext, FileStream fileStream, int numThreads) { SpinWait spinWait = new SpinWait(); while (!transferContext.IsComplete && !transferContext.CancellationToken.IsCancellationRequested) { if (!transferContext.IsReadingOrWriting) { DoSequentialRead(transferContext, fileStream); } if (!transferContext.IsComplete && transferContext.NumInProgressUploadDownloads < numThreads) { TryUploadingBlocks(transferContext); } spinWait.SpinOnce(); } while (transferContext.NumInProgressUploadDownloads > 0 || transferContext.IsReadingOrWriting) { spinWait.SpinOnce(); } //Release any buffers that are still in queue to be written to file but could not because there was // a complete signal for this file upload due to some error in the one of the other block uploads in the same transfer context. //If this is not cleaned, used buffers will hit the cap of 16 and future uploads will hang for lack of memory buffers. for (int currentBlock = transferContext.NextFileIOBlock; currentBlock <= transferContext.BlocksForFileIO.Count(); currentBlock++) { byte[] buffer = null; if (transferContext.BlocksForFileIO.TryGetValue(currentBlock, out buffer) && (buffer != null)) { try { transferContext.MemoryManager.ReleaseBuffer(buffer); } catch (ArgumentException ex) { Debug.WriteLine("Exception occured while releasing memory buffer ", ex.Message); } } } foreach (var memoryStream in transferContext.BufferStreams.Values) { memoryStream.Dispose(); } transferContext.OnComplete(); }
/// <summary>Tries to dequeue an element from the queue.</summary> public bool TryDequeue(out T item) { // Loop in case of contention... var spinner = new SpinWait(); while (true) { // Get the head at which to try to dequeue. int currentHead = Volatile.Read(ref _headAndTail.Head); int slotsIndex = currentHead & _slotsMask; // Read the sequence number for the head position. int sequenceNumber = Volatile.Read(ref _slots[slotsIndex].SequenceNumber); // We can dequeue from this slot if it's been filled by an enqueuer, which // would have left the sequence number at pos+1. int diff = sequenceNumber - (currentHead + 1); if (diff == 0) { // We may be racing with other dequeuers. Try to reserve the slot by incrementing // the head. Once we've done that, no one else will be able to read from this slot, // and no enqueuer will be able to read from this slot until we've written the new // sequence number. WARNING: The next few lines are not reliable on a runtime that // supports thread aborts. If a thread abort were to sneak in after the CompareExchange // but before the Volatile.Write, enqueuers trying to enqueue into this slot would // spin indefinitely. If this implementation is ever used on such a platform, this // if block should be wrapped in a finally / prepared region. if (Interlocked.CompareExchange(ref _headAndTail.Head, currentHead + 1, currentHead) == currentHead) { // Successfully reserved the slot. Note that after the above CompareExchange, other threads // trying to dequeue from this slot will end up spinning until we do the subsequent Write. item = _slots[slotsIndex].Item; if (!Volatile.Read(ref _preservedForObservation)) { // If we're preserving, though, we don't zero out the slot, as we need it for // enumerations, peeking, ToArray, etc. And we don't update the sequence number, // so that an enqueuer will see it as full and be forced to move to a new segment. _slots[slotsIndex].Item = default(T); Volatile.Write(ref _slots[slotsIndex].SequenceNumber, currentHead + _slots.Length); } return(true); } } else if (diff < 0) { // The sequence number was less than what we needed, which means this slot doesn't // yet contain a value we can dequeue, i.e. the segment is empty. Technically it's // possible that multiple enqueuers could have written concurrently, with those // getting later slots actually finishing first, so there could be elements after // this one that are available, but we need to dequeue in order. So before declaring // failure and that the segment is empty, we check the tail to see if we're actually // empty or if we're just waiting for items in flight or after this one to become available. bool frozen = _frozenForEnqueues; int currentTail = Volatile.Read(ref _headAndTail.Tail); if (currentTail - currentHead <= 0 || (frozen && (currentTail - FreezeOffset - currentHead <= 0))) { item = default(T); return(false); } // It's possible it could have become frozen after we checked _frozenForEnqueues // and before reading the tail. That's ok: in that rare race condition, we just // loop around again. } // Lost a race. Spin a bit, then try again. spinner.SpinOnce(); } }
/// <summary> /// Takes a moment-in-time snapshot of the deque. /// </summary> /// <returns>A list representing a moment-in-time snapshot of the deque.</returns> /// <remarks> /// The algorithm runs in linear O(n) time. /// /// This implementation relies on the following invariant: /// If at time t, x was the leftmost node and y was the rightmost node, /// regardless of how many nodes are pushed/popped from either end thereafter, the paths /// (a) x->a (obtained by traversing the deque recursively using a node's right pointer starting from x), and /// (b) y->b (obtained by traversing the deque recursively using a node's left pointer starting from y) /// will always have at least 1 node in common. /// /// This means that, for a given x and y, even if the deque is mutated during the algorithm's /// execution, we can always rebuild the original x-y sequence by finding a node c, common to both /// x->a and y->b paths, and merging the paths by the common node. /// </remarks> private List <T> ToList() { //try to grab a reference to a stable anchor (fast route) Anchor anchor = _anchor; anchor.Validate(); //try to grab a reference to a stable anchor (slow route) if (anchor._status != DequeStatus.Stable) { var spinner = new SpinWait(); do { anchor = _anchor; anchor.Validate(); spinner.SpinOnce(); } while (anchor._status != DequeStatus.Stable); } var x = anchor._left; var y = anchor._right; //check if deque is empty if (x == null) { return(new List <T>()); } //check if deque has only 1 item if (x == y) { return new List <T> { x._value } } ; var xaPath = new List <Node>(); var current = x; while (current != null && current != y) { xaPath.Add(current); current = current._right; } /* * If the 'y' node hasn't been popped from the right side of the deque, * then we should still be able to find the original x-y sequence * using a node's right pointer. * * If 'current' does not equal 'y', then the 'y' node must have been popped by * another thread during the while loop and the traversal wasn't successful. */ if (current == y) { xaPath.Add(current); return(xaPath.Select(node => node._value).ToList()); } /* * If the 'y' node has been popped from the right end, we need to find all nodes that have * been popped from the right end and rebuild the original sequence. * * To do this, we need to traverse the deque from right to left (using a node's left pointer) * until we find a node c common to both x->a and y->b paths. Such a node is either: * (a) currently part of the deque or * (b) the last node of the x->a path (i.e., node 'a') or * (c) the last node to be popped from the left (if all nodes between 'x' and 'y' were popped from the deque). * * -- Predicate (a) -- * A node belongs to the deque if node.left.right == node (except for the leftmost node) if the deque has > 1 nodes. * If the deque has exactly one node, we know we've found that node if: * (1) all nodes to its right in the x-y sequence don't fall under predicates (a), (b) and (c) and * (2) node.left == null * * -- Predicate (b) -- * True for a node n if n == a * * -- Predicate (c) -- * True for a node n if: * (1) all nodes to its right in the x-y sequence don't fall under predicates (a), (b) and (c) and * (2) node.left == null */ current = y; var a = xaPath.Last(); var ycPath = new Stack <Node>(); while (current._left != null && current._left._right != current && current != a) { ycPath.Push(current); current = current._left; } //this node is common to the list and the stack var common = current; ycPath.Push(common); /* * Merge the x->a and the y->c paths by the common node. * This is done by removing the nodes in x->a that come after c, * and appending all nodes in the y->c path in reverse order. * Since we used a LIFO stack to store all nodes in the y->c path, * we can simply iterate over it to reverse the order in which they were inserted. */ var xySequence = xaPath .TakeWhile(node => node != common) .Select(node => node._value) .Concat( ycPath.Select(node => node._value)); return(xySequence.ToList()); }
// Flushes the changes such that they are in sync with the FileStream bits (ones obtained // with the win32 ReadFile and WriteFile functions). Need to call FileStream's Flush to // flush to the disk. // NOTE: This will flush all bytes before and after the view up until an offset that is a multiple // of SystemPageSize. public void Flush(UIntPtr capacity) { unsafe { byte *firstPagePtr = null; try { _viewHandle.AcquirePointer(ref firstPagePtr); if (Interop.Kernel32.FlushViewOfFile((IntPtr)firstPagePtr, capacity)) { return; } // It is a known issue within the NTFS transaction log system that // causes FlushViewOfFile to intermittently fail with ERROR_LOCK_VIOLATION // As a workaround, we catch this particular error and retry the flush operation // a few milliseconds later. If it does not work, we give it a few more tries with // increasing intervals. Eventually, however, we need to give up. In ad-hoc tests // this strategy successfully flushed the view after no more than 3 retries. int error = Marshal.GetLastWin32Error(); if (error != Interop.Errors.ERROR_LOCK_VIOLATION) { throw Win32Marshal.GetExceptionForWin32Error(error); } SpinWait spinWait = default; for (int w = 0; w < MaxFlushWaits; w++) { int pause = (1 << w); // MaxFlushRetries should never be over 30 Thread.Sleep(pause); for (int r = 0; r < MaxFlushRetriesPerWait; r++) { if (Interop.Kernel32.FlushViewOfFile((IntPtr)firstPagePtr, capacity)) { return; } error = Marshal.GetLastWin32Error(); if (error != Interop.Errors.ERROR_LOCK_VIOLATION) { throw Win32Marshal.GetExceptionForWin32Error(error); } spinWait.SpinOnce(); } } // We got to here, so there was no success: throw Win32Marshal.GetExceptionForWin32Error(error); } finally { if (firstPagePtr != null) { _viewHandle.ReleasePointer(); } } } }
internal bool AtomicLoopStateUpdate(int newState, int illegalStates, ref int oldState) { SpinWait sw = new SpinWait(); do { oldState = m_LoopStateFlags; if ((oldState & illegalStates) != 0) return false; if (Interlocked.CompareExchange(ref m_LoopStateFlags, oldState | newState, oldState) == oldState) { return true; } sw.SpinOnce(); } while (true); }
public static void TestCreationOptions(String ctorType) { ConcurrentExclusiveSchedulerPair schedPair = null; //Need to define the default values since these values are passed to the verification methods TaskScheduler scheduler = TaskScheduler.Default; int maxConcurrentLevel = Environment.ProcessorCount; //Based on input args, use one of the ctor overloads switch (ctorType.ToLower()) { case "default": schedPair = new ConcurrentExclusiveSchedulerPair(); break; case "scheduler": schedPair = new ConcurrentExclusiveSchedulerPair(scheduler); break; case "maxconcurrent": maxConcurrentLevel = 2; schedPair = new ConcurrentExclusiveSchedulerPair(scheduler, maxConcurrentLevel); break; case "all": maxConcurrentLevel = Int32.MaxValue; schedPair = new ConcurrentExclusiveSchedulerPair(scheduler, -1 /*MaxConcurrentLevel*/, -1 /*MaxItemsPerTask*/); //-1 gets converted to Int32.MaxValue break; default: throw new NotImplementedException(String.Format("The option specified {0} to create the ConcurrentExclusiveSchedulerPair is invalid", ctorType)); } //Create the factories that use the exclusive scheduler and the concurrent scheduler. We test to ensure //that the ConcurrentExclusiveSchedulerPair created are valid by scheduling work on them. TaskFactory writers = new TaskFactory(schedPair.ExclusiveScheduler); TaskFactory readers = new TaskFactory(schedPair.ConcurrentScheduler); List <Task> taskList = new List <Task>(); //Store all tasks created, to enable wait until all of them are finished // Schedule some dummy work that should be run with as much parallelism as possible for (int i = 0; i < 50; i++) { //In the current design, when there are no more tasks to execute, the Task used by concurrentexclusive scheduler dies //by sleeping we simulate some non trivial work that takes time and causes the concurrentexclusive scheduler Task //to stay around for addition work. taskList.Add(readers.StartNew(() => { var sw = new SpinWait(); while (!sw.NextSpinWillYield) { sw.SpinOnce(); } })); } // Schedule work where each item must be run when no other items are running for (int i = 0; i < 10; i++) { taskList.Add(writers.StartNew(() => { var sw = new SpinWait(); while (!sw.NextSpinWillYield) { sw.SpinOnce(); } })); } //Wait on the tasks to finish to ensure that the ConcurrentExclusiveSchedulerPair created can schedule and execute tasks without issues foreach (var item in taskList) { item.Wait(); } //verify that maxconcurrency was respected. if (ctorType == "maxconcurrent") { Assert.Equal(maxConcurrentLevel, schedPair.ConcurrentScheduler.MaximumConcurrencyLevel); } Assert.Equal(1, schedPair.ExclusiveScheduler.MaximumConcurrencyLevel); //verify that the schedulers have not completed Assert.False(schedPair.Completion.IsCompleted, "The schedulers should not have completed as a completion request was not issued."); //complete the scheduler and make sure it shuts down successfully schedPair.Complete(); schedPair.Completion.Wait(); //make sure no additional work may be scheduled foreach (var schedPairScheduler in new TaskScheduler[] { schedPair.ConcurrentScheduler, schedPair.ExclusiveScheduler }) { Exception caughtException = null; try { Task.Factory.StartNew(() => { }, CancellationToken.None, TaskCreationOptions.None, schedPairScheduler); } catch (Exception exc) { caughtException = exc; } Assert.True( caughtException is TaskSchedulerException && caughtException.InnerException is InvalidOperationException, "Queueing after completion should fail"); } }
/// <summary> /// Attempts to pass the gate if it is open /// </summary> public MutuallyExclusiveGuard EnterClient(int timeout, CancellationToken token) { if (_isDisposed) { throw new ObjectDisposedException(this.GetType().Name); } if (token.IsCancellationRequested) { throw new OperationCanceledException(token); } try { Interlocked.Increment(ref _waiterCount); if (TryEnterClient()) // Always call TryEnterClient first { return(new MutuallyExclusiveGuard(this)); } uint startTime = 0; if (timeout > 0) { startTime = TimeoutHelper.GetTimestamp(); } else if (timeout < -1) { timeout = Timeout.Infinite; } if (timeout != 0) { SpinWait sw = new SpinWait(); while (!_isDisposed) { int remainingWaitMilliseconds = Timeout.Infinite; if (timeout != Timeout.Infinite) { remainingWaitMilliseconds = TimeoutHelper.UpdateTimeout(startTime, timeout); if (remainingWaitMilliseconds <= 0) { return(new MutuallyExclusiveGuard()); } } if (_event.Wait(remainingWaitMilliseconds, token) && !_isDisposed) { if (TryEnterClient()) { return(new MutuallyExclusiveGuard(this)); } sw.SpinOnce(); // State swap perfromed before manipulations on _event => Should wait some time } } if (_isDisposed) { throw new ObjectDisposedException(this.GetType().Name); } } return(new MutuallyExclusiveGuard()); } finally { Interlocked.Decrement(ref _waiterCount); } }
private static void Run161() { if (_useDelay) { Thread.Sleep(_delayCount); } int count = 0; Console.WriteLine("========================="); var result = _redisClient4.FlushDBAsync().Result; Console.WriteLine($"Clear DB 0 - [{(result ? "SUCCEED" : "FAILED")}]!"); var tasks = new Task <bool> [frequence]; Stopwatch sw = new Stopwatch(); //_beforeSw?.Invoke(title); Console.WriteLine("Start Run:"); //Thread.Sleep(0); //Thread.Sleep(1000); sw.Start(); Parallel.For(0, frequence, _options, (index) => { var key = index.ToString(); tasks[index] = _redisClient161.SetAsync(key, key); }); //Task.WaitAll(tasks); int offset = 0; SpinWait wait = default; while (offset != frequence - 1) { for (int i = offset; i < frequence; i++) { if (tasks[i].IsCompleted) { offset = i; } else { break; } } wait.SpinOnce(); } sw.Stop(); //Thread.Sleep(3000); //var checkTasks = new Task[frequence]; //for (var a = 0; a < frequence; a += 1) //{ // var key = a.ToString(); // checkTasks[a] = Task.Run(() => // { // var result = _stackExnchangeClient.StringGet(key); // if (result != key) // { // Console.WriteLine(key); // Console.WriteLine(result); // Interlocked.Increment(ref count); // } // }); //} //Task.WaitAll(checkTasks); //Console.WriteLine($"{title} (0-{frequence / 10000}W) : {sw.ElapsedTicks} SPAN! "); Console.WriteLine($"161 (0-{frequence / 10000}W) : {sw.ElapsedMilliseconds}ms! "); //Console.WriteLine($"Errors : {count} !"); //if (count>0) //{ // Thread.Sleep(1000); // for (var a = 0; a < frequence; a += 1) // { // var key = a.ToString(); // tasks[a] = Task.Run(() => // { // var result = _stackExnchangeClient.StringGet(key); // if (result != key) // { // Interlocked.Increment(ref count); // } // }); // } // Task.WaitAll(tasks); // Console.WriteLine($"Rechecking Errors : {count} !"); //} Console.WriteLine("=========================\r\n"); }
/// <summary> /// Stops the current <see cref="ThreadSetManager"/> /// </summary> /// <param name="waitForStop">Whether the current thread should be blocked until all processing threads are be completed</param> private void StopThreadManager(bool waitForStop) { if (this.IsStopRequestedOrStopped) { if (waitForStop) { this.Join(); } } ThreadSetManagerState prevState; if (!ChangeStateSafe(ThreadSetManagerState.StopRequested, out prevState)) { if (prevState != ThreadSetManagerState.StartRequested) { if (waitForStop) { this.Join(); } return; } SpinWait sw = new SpinWait(); while (State == ThreadSetManagerState.StartRequested) { sw.SpinOnce(); } if (!ChangeStateSafe(ThreadSetManagerState.StopRequested, out prevState)) { if (waitForStop) { this.Join(); } return; } } _stopRequestedCancelation.Cancel(); if (waitForStop && prevState != ThreadSetManagerState.Created) { for (int i = 0; i < _procThreads.Length; i++) { if (_procThreads[i] != null) { _procThreads[i].Join(); } } } if (ActiveThreadCount == 0) { if (ChangeStateSafe(ThreadSetManagerState.Stopped, out prevState) && prevState == ThreadSetManagerState.StopRequested) { _threadExitedEvent.Set(); Profiling.Profiler.ThreadSetManagerDisposed(this.Name, false); } } Debug.Assert(State == ThreadSetManagerState.StopRequested || State == ThreadSetManagerState.Stopped); Debug.Assert(!waitForStop || State == ThreadSetManagerState.Stopped); }
private void ThreadProcFunc() { CancellationToken token = GetCancellationToken(); object state = null; try { Interlocked.Increment(ref _activeThreadCount); Profiling.Profiler.ThreadSetManagerThreadStart(this.Name, this.ActiveThreadCount, this.ThreadCount); state = this.Prepare(); token.ThrowIfCancellationRequested(); this.Process(state, token); } catch (OperationCanceledException opEx) { if (!token.IsCancellationRequested) { ProcessThreadException(opEx); throw; } } catch (Exception ex) { if (ex.GetType() == typeof(ThreadAbortException) || ex.GetType() == typeof(ThreadInterruptedException) || ex.GetType() == typeof(StackOverflowException) || ex.GetType() == typeof(OutOfMemoryException)) { throw; } ProcessThreadException(ex); throw; } finally { this.Finalize(state); int activeThreadCount = Interlocked.Decrement(ref _activeThreadCount); int exitedThreadCount = Interlocked.Increment(ref _exitedThreadCount); Debug.Assert(activeThreadCount >= 0); Debug.Assert(exitedThreadCount <= this.ThreadCount); if (exitedThreadCount >= this.ThreadCount || (activeThreadCount == 0 && IsStopRequested)) { // Вынуждены ждать SpinWait sw = new SpinWait(); while (State == ThreadSetManagerState.StartRequested) { sw.SpinOnce(); } ThreadSetManagerState prevState; if (ChangeStateSafe(ThreadSetManagerState.AllThreadsExited, out prevState)) { Debug.Assert(prevState == ThreadSetManagerState.Running); _threadExitedEvent.Set(); } else if (ChangeStateSafe(ThreadSetManagerState.Stopped, out prevState)) { Debug.Assert(prevState == ThreadSetManagerState.StopRequested); _threadExitedEvent.Set(); Profiling.Profiler.ThreadSetManagerDisposed(this.Name, false); } } Profiling.Profiler.ThreadSetManagerThreadStop(this.Name, this.ActiveThreadCount, this.ThreadCount); } }
private object WaitForCompletion(bool snap) { ManualResetEvent waitHandle = null; bool createdByMe = false; bool complete = snap ? IsCompleted : InternalPeekCompleted; if (!complete) { // Not done yet, so wait: waitHandle = (ManualResetEvent)_event; if (waitHandle == null) { createdByMe = LazilyCreateEvent(out waitHandle); } } if (waitHandle != null) { try { GlobalLog.Print("LazyAsyncResult#" + Logging.HashString(this) + "::InternalWaitForCompletion() Waiting for completion _event#" + Logging.HashString(waitHandle)); waitHandle.WaitOne(Timeout.Infinite); } catch (ObjectDisposedException) { // This can occur if this method is called from two different threads. // This possibility is the trade-off for not locking. } finally { // We also want to dispose the event although we can't unless we did wait on it here. if (createdByMe && !_userEvent) { // Does _userEvent need to be volatile (or _event set via Interlocked) in order // to avoid giving a user a disposed event? ManualResetEvent oldEvent = (ManualResetEvent)_event; _event = null; if (!_userEvent) { oldEvent.Dispose(); } } } } // A race condition exists because InvokeCallback sets _intCompleted before _result (so that _result // can benefit from the synchronization of _intCompleted). That means you can get here before _result got // set (although rarely - once every eight hours of stress). Handle that case with a spin-lock. SpinWait sw = new SpinWait(); while (_result == DBNull.Value) { sw.SpinOnce(); } GlobalLog.Print("LazyAsyncResult#" + Logging.HashString(this) + "::InternalWaitForCompletion() done: " + (_result is Exception ? ((Exception)_result).Message : _result == null ? "<null>" : _result.ToString())); return(_result); }
private async void Connection_RequestReceived(AppServiceConnection sender, AppServiceRequestReceivedEventArgs args) { AppServiceDeferral Deferral = args.GetDeferral(); try { AppServiceConnection ServerConnection; SpinWait Spin = new SpinWait(); Stopwatch Watch = new Stopwatch(); Watch.Start(); while (!PairedConnections.TryGetValue(sender, out ServerConnection) && Watch.ElapsedMilliseconds < 5000) { if (Spin.NextSpinWillYield) { await Task.Delay(500); } else { Spin.SpinOnce(); } } Watch.Stop(); if (ServerConnection != null) { AppServiceResponse ServerRespose = await ServerConnection.SendMessageAsync(args.Request.Message); if (ServerRespose.Status == AppServiceResponseStatus.Success) { await args.Request.SendResponseAsync(ServerRespose.Message); } else { await args.Request.SendResponseAsync(new ValueSet { { "Error", "Can't not send message to server" } }); } } else { ValueSet Value = new ValueSet { { "Error", "Failed to wait a server connection within the specified time" } }; await args.Request.SendResponseAsync(Value); } } catch { ValueSet Value = new ValueSet { { "Error", "Some exceptions were threw while transmitting the message" } }; await args.Request.SendResponseAsync(Value); } finally { Deferral.Complete(); } }
public void Wait() { _spinWait.SpinOnce(); }
internal static void Peak(ref StatisticsState state, TimeSpan time, long value) { StatisticsState State; var Wait = new SpinWait(); for (; ;) { State = Volatile.Read(ref state); var Interval = State._Interval; if (Interval == TimeSpan.Zero) { var OldValue = Volatile.Read(ref State._Current); if (OldValue >= value || Interlocked.CompareExchange(ref State._Current, value, OldValue) >= value) { return; } continue; } var Finish = State._Time + Interval; if (time < Finish) { // Still within the time interval var OldValue = Volatile.Read(ref State._Current); if (OldValue == -1) { // Expired. Wait a moment for the other thread to finish replacing the state Wait.SpinOnce(); } else { if (OldValue >= value || Interlocked.CompareExchange(ref State._Current, value, OldValue) >= value) { return; } // Another thread replaced our value with something greater than the previous peak, but less than our new peak } } else if (time < Finish + Interval) { // We're within the next time interval, flag the state as expired so we can lock in that interval var Previous = Interlocked.Exchange(ref State._Current, -1); if (Previous != -1) { var NewState = new StatisticsState(Interval, time, value, Previous); // Replace the current state with a new state if (Interlocked.CompareExchange(ref state, NewState, State) == State) { return; } } else { // Wait a moment for the other thread to finish replacing the state Wait.SpinOnce(); } // Another thread is performing a replacement, wait and try again } else { // Two intervals have passed since this state began recording, so we replace with a zero previous record var NewState = new StatisticsState(Interval, time, value); // Replace the current state with a new state if (Interlocked.CompareExchange(ref state, NewState, State) == State) { return; } // Another thread is performing a replacement, wait and try again } } }
public static void TestSchedulerNesting() { // Create a hierarchical set of scheduler pairs var cespParent = new ConcurrentExclusiveSchedulerPair(); var cespChild1 = new ConcurrentExclusiveSchedulerPair(cespParent.ConcurrentScheduler); var cespChild1Child1 = new ConcurrentExclusiveSchedulerPair(cespChild1.ConcurrentScheduler); var cespChild1Child2 = new ConcurrentExclusiveSchedulerPair(cespChild1.ExclusiveScheduler); var cespChild2 = new ConcurrentExclusiveSchedulerPair(cespParent.ExclusiveScheduler); var cespChild2Child1 = new ConcurrentExclusiveSchedulerPair(cespChild2.ConcurrentScheduler); var cespChild2Child2 = new ConcurrentExclusiveSchedulerPair(cespChild2.ExclusiveScheduler); // these are ordered such that we will complete the child schedulers before we complete their parents. That way // we don't complete a parent that's still in use. var cesps = new[] { cespChild1Child1, cespChild1Child2, cespChild1, cespChild2Child1, cespChild2Child2, cespChild2, cespParent, }; // Get the schedulers from all of the pairs List <TaskScheduler> schedulers = new List <TaskScheduler>(); foreach (var s in cesps) { schedulers.Add(s.ConcurrentScheduler); schedulers.Add(s.ExclusiveScheduler); } // Keep track of all created tasks var tasks = new List <Task>(); // Queue lots of work to each scheduler foreach (var scheduler in schedulers) { // Create a function that schedules and inlines recursively queued tasks Action <int> recursiveWork = null; recursiveWork = depth => { if (depth > 0) { Action work = () => { var sw = new SpinWait(); while (!sw.NextSpinWillYield) { sw.SpinOnce(); } recursiveWork(depth - 1); }; TaskFactory factory = new TaskFactory(scheduler); Debug.WriteLine(string.Format("Start tasks in scheduler {0}", scheduler.Id)); Task t1 = factory.StartNew(work); Task t2 = factory.StartNew(work); Task t3 = factory.StartNew(work); Task.WaitAll(t1, t2, t3); } }; for (int i = 0; i < 2; i++) { tasks.Add(Task.Factory.StartNew(() => recursiveWork(2), CancellationToken.None, TaskCreationOptions.None, scheduler)); } } // Wait for all tasks to complete, then complete the schedulers Task.WaitAll(tasks.ToArray()); foreach (var cesp in cesps) { cesp.Complete(); cesp.Completion.Wait(); } }
protected virtual void Dispose(bool disposing) { if (!disposed.TryRelaxedSet()) return; if (handle != null) { ManualResetEvent tmpHandle = Interlocked.Exchange(ref handle, null); if (used > 0) { // A tiny wait (just a few cycles normally) before releasing var wait = new SpinWait(); while (used > 0) wait.SpinOnce(); } tmpHandle.Close(); } }
public long Allocate(int numSlots = 1) { PageOffset localTailPageOffset = default(PageOffset); // Determine insertion index. // ReSharper disable once CSharpWarnings::CS0420 #pragma warning disable 420 localTailPageOffset.PageAndOffset = Interlocked.Add(ref TailPageOffset.PageAndOffset, numSlots); #pragma warning restore 420 int page = localTailPageOffset.Page; int offset = localTailPageOffset.Offset - numSlots; #region HANDLE PAGE OVERFLOW /* To prove correctness of the following modifications * done to TailPageOffset and the allocation itself, * we should use the fact that only one thread will have any * of the following cases since it is a counter and we spin-wait * until the tail is folded onto next page accordingly. */ if (localTailPageOffset.Offset >= PageSize) { if (offset >= PageSize) { //The tail offset value was more than page size before atomic add //We consider that a failed attempt and retry again var spin = new SpinWait(); do { //Just to give some more time to the thread // that is handling this overflow while (TailPageOffset.Offset >= PageSize) { spin.SpinOnce(); } // ReSharper disable once CSharpWarnings::CS0420 #pragma warning disable 420 localTailPageOffset.PageAndOffset = Interlocked.Add(ref TailPageOffset.PageAndOffset, numSlots); #pragma warning restore 420 page = localTailPageOffset.Page; offset = localTailPageOffset.Offset - numSlots; } while (offset >= PageSize); } if (localTailPageOffset.Offset == PageSize) { //Folding over at page boundary localTailPageOffset.Page++; localTailPageOffset.Offset = 0; TailPageOffset = localTailPageOffset; } else if (localTailPageOffset.Offset >= PageSize) { //Overflows not allowed. We allot same space in next page. localTailPageOffset.Page++; localTailPageOffset.Offset = numSlots; TailPageOffset = localTailPageOffset; page = localTailPageOffset.Page; offset = 0; } } #endregion long address = (((long)page) << LogPageSizeBits) | ((long)offset); // Check if TailPageIndex is appropriate and allocated! int pageIndex = page % BufferSize; if (TailPageIndex == pageIndex) { return(address); } //Invert the address if either the previous page is not flushed or if it is null if ((PageStatusIndicator[pageIndex].PageFlushCloseStatus.PageFlushStatus != FlushStatus.Flushed) || (PageStatusIndicator[pageIndex].PageFlushCloseStatus.PageCloseStatus != CloseStatus.Closed) || (values[pageIndex] == null)) { address = -address; } // Update the read-only so that we can get more space for the tail if (offset == 0) { if (address >= 0) { TailPageIndex = pageIndex; Interlocked.MemoryBarrier(); } long newPage = page + 1; int newPageIndex = (int)((page + 1) % BufferSize); long tailAddress = (address < 0 ? -address : address); PageAlignedShiftReadOnlyAddress(tailAddress); PageAlignedShiftHeadAddress(tailAddress); if (values[newPageIndex] == null) { AllocatePage(newPageIndex); } } return(address); }
/// <summary> /// Helper method of GetEnumerator to separate out yield return statement, and prevent lazy evaluation. /// </summary> private IEnumerator <T> GetEnumerator(Segment head, Segment tail, int headLow, int tailHigh) { try { SpinWait spin = new SpinWait(); if (head == tail) { for (int i = headLow; i <= tailHigh; i++) { // If the position is reserved by an Enqueue operation, but the value is not written into, // spin until the value is available. spin.Reset(); while (!head._state[i]._value) { spin.SpinOnce(); } yield return(head._array[i]); } } else { //iterate on head segment for (int i = headLow; i < SEGMENT_SIZE; i++) { // If the position is reserved by an Enqueue operation, but the value is not written into, // spin until the value is available. spin.Reset(); while (!head._state[i]._value) { spin.SpinOnce(); } yield return(head._array[i]); } //iterate on middle segments Segment curr = head.Next; while (curr != tail) { for (int i = 0; i < SEGMENT_SIZE; i++) { // If the position is reserved by an Enqueue operation, but the value is not written into, // spin until the value is available. spin.Reset(); while (!curr._state[i]._value) { spin.SpinOnce(); } yield return(curr._array[i]); } curr = curr.Next; } //iterate on tail segment for (int i = 0; i <= tailHigh; i++) { // If the position is reserved by an Enqueue operation, but the value is not written into, // spin until the value is available. spin.Reset(); while (!tail._state[i]._value) { spin.SpinOnce(); } yield return(tail._array[i]); } } } finally { // This Decrement must happen after the enumeration is over. Interlocked.Decrement(ref _numSnapshotTakers); } }
/// <summary> /// Removes the first element from the queue and returns it (or <c>null</c>). /// </summary> /// <param name="blockWhenEmpty"> /// If <c>true</c> and the queue is empty, the calling thread is blocked until /// either an element is enqueued, or <see cref="Stop"/> is called. /// </param> /// <returns> /// <list type="bullet"> /// <item> /// <term>If the queue not empty</term> /// <description>the first element.</description> /// </item> /// <item> /// <term>otherwise, if <paramref name="blockWhenEmpty"/>==<c>false</c> /// or <see cref="Stop"/> has been called</term> /// <description><c>null</c>.</description> /// </item> /// </list> /// </returns> public Event Dequeue(bool blockWhenEmpty) { SpinWait sw = new SpinWait(); do { int cachedRemoveId = _removeId; int cachedAddId = _addId; // Empty case if (cachedRemoveId == cachedAddId) { if (!blockWhenEmpty || _stopped != 0) { return(null); } // Spin a few times to see if something changes if (sw.Count <= spinCount) { sw.SpinOnce(); } else { // Reset to wait for an enqueue _mreAdd.Reset(); // Recheck for an enqueue to avoid a Wait if (cachedRemoveId != _removeId || cachedAddId != _addId) { // Queue is not empty, set the event _mreAdd.Set(); continue; } // Wait for something to happen _mreAdd.Wait(500); } continue; } // Validate that we are the current dequeuer if (Interlocked.CompareExchange(ref _removeId, cachedRemoveId + 1, cachedRemoveId) != cachedRemoveId) { continue; } // Dequeue our work item Event e; while (!_queue.TryDequeue(out e)) { if (!blockWhenEmpty || _stopped != 0) { return(null); } } return(e); } while (true); }
/// <summary> /// Attempts to remove and return an item from the left end of the <see cref="ConcurrentDeque{T}"/>. /// </summary> /// <param name="item">When this method returns, if the operation was successful, <paramref name="item"/> contains the /// object removed. If no object was available to be removed, the value is unspecified.</param> /// <returns>true if an element was removed and returned succesfully; otherwise, false.</returns> public bool TryPopLeft(out T item) { Anchor anchor; var spinner = new SpinWait(); while (true) { anchor = _anchor; anchor.Validate(); if (anchor._left == null) { //return false if the deque is empty item = default(T); return(false); } if (anchor._right == anchor._left) { //update both pointers if the deque has only one node var newAnchor = new Anchor(); if (Interlocked.CompareExchange(ref _anchor, newAnchor, anchor) == anchor) { break; } } else if (anchor._status == DequeStatus.Stable) { //update left pointer if deque has > 1 node var prev = anchor._left._right; var newAnchor = new Anchor(prev, anchor._right, anchor._status); if (Interlocked.CompareExchange(ref _anchor, newAnchor, anchor) == anchor) { break; } } else { //if the deque is unstable, //attempt to bring it to a stable state before trying to remove the node. Stabilize(anchor); } spinner.SpinOnce(); } var node = anchor._left; item = node._value; /* * Try to set the new leftmost node's left pointer to null to avoid memory leaks. * We try only once - if CAS fails, then another thread must have pushed a new node, in which case we simply carry on. */ var leftmostNode = node._right; if (leftmostNode != null) { Interlocked.CompareExchange(ref leftmostNode._left, null, node); } return(true); }
public static int WaitAny(Task[] tasks, int millisecondsTimeout, CancellationToken cancellationToken) { if (tasks == null) { throw new ArgumentNullException("tasks"); } if (tasks.Length == 0) { throw new ArgumentException("tasks is empty", "tasks"); } if (tasks.Length == 1) { tasks[0].Wait(millisecondsTimeout, cancellationToken); return(0); } int numFinished = 0; int indexFirstFinished = -1; int index = 0; TaskScheduler sched = null; Task task = null; Watch watch = Watch.StartNew(); ManualResetEventSlim predicateEvt = new ManualResetEventSlim(false); foreach (Task t in tasks) { int indexResult = index++; t.ContinueWith(delegate { if (numFinished >= 1) { return; } int result = Interlocked.Increment(ref numFinished); // Check if we are the first to have finished if (result == 1) { indexFirstFinished = indexResult; } // Stop waiting predicateEvt.Set(); }, TaskContinuationOptions.ExecuteSynchronously); if (sched == null && t.scheduler != null) { task = t; sched = t.scheduler; } } // If none of task have a scheduler we are forced to wait for at least one to start if (sched == null) { var handles = Array.ConvertAll(tasks, t => t.schedWait.WaitHandle); int shandle = -1; if ((shandle = WaitHandle.WaitAny(handles, millisecondsTimeout)) == WaitHandle.WaitTimeout) { return(-1); } sched = tasks[shandle].scheduler; task = tasks[shandle]; millisecondsTimeout = ComputeTimeout(millisecondsTimeout, watch); } // One task already finished if (indexFirstFinished != -1) { return(indexFirstFinished); } if (cancellationToken != CancellationToken.None) { cancellationToken.Register(predicateEvt.Set); cancellationToken.ThrowIfCancellationRequested(); } sched.ParticipateUntil(task, predicateEvt, millisecondsTimeout); // Index update is still not done if (indexFirstFinished == -1) { SpinWait wait = new SpinWait(); while (indexFirstFinished == -1) { wait.SpinOnce(); } } return(indexFirstFinished); }
// This is the actual method called in the Thread void WorkerMethodWrapper () { int sleepTime = 0; SpinWait wait = new SpinWait (); // Main loop while (started == 1) { bool result = false; result = WorkerMethod (); // Wait a little and if the Thread has been more sleeping than working shut it down wait.SpinOnce (); if (result) sleepTime = 0; if (sleepTime++ > sleepThreshold) break; } started = 0; }
public void ParallelForEachTestCase () { ParallelTestHelper.Repeat (() => { IEnumerable<int> e = Enumerable.Repeat(1, 500); ConcurrentQueue<int> queue = new ConcurrentQueue<int> (); SpinWait sw = new SpinWait (); int count = 0; Parallel.ForEach (e, (element) => { Interlocked.Increment (ref count); queue.Enqueue (element); sw.SpinOnce (); }); Assert.AreEqual (500, count, "#1"); CollectionAssert.AreEquivalent (e, queue, "#2"); }); }
// Almost same as above but with an added predicate and treating one item at a time. // It's used by Scheduler Participate(...) method for special waiting case like // Task.WaitAll(someTasks) or Task.WaitAny(someTasks) // Predicate should be really fast and not blocking as it is called a good deal of time // Also, the method skip tasks that are LongRunning to avoid blocking (Task are not LongRunning by default) public static void WorkerMethod (Func<bool> predicate, IProducerConsumerCollection<Task> sharedWorkQueue, ThreadWorker[] others) { SpinWait wait = new SpinWait (); while (!predicate ()) { Task value; // Dequeue only one item as we have restriction if (sharedWorkQueue.TryTake (out value)) { if (value != null) { if (CheckTaskFitness (value)) value.Execute (null); else sharedWorkQueue.TryAdd (value); } } // First check to see if we comply to predicate if (predicate ()) return; // Try to complete other work by stealing since our desired tasks may be in other worker ThreadWorker other; for (int i = 0; i < others.Length; i++) { if ((other = others [i]) == null) continue; if (other.dDeque.PopTop (out value) == PopResult.Succeed) { if (value != null) { if (CheckTaskFitness (value)) value.Execute (null); else sharedWorkQueue.TryAdd (value); } } if (predicate ()) return; } wait.SpinOnce (); } }
public static void SpinUntil (Func<bool> condition) { SpinWait sw = new SpinWait (); while (!condition ()) sw.SpinOnce (); }
private bool TryAddWithNoTimeValidation(T item, int millisecondsTimeout, CancellationToken cancellationToken) { bool flag; CheckDisposed(); if (cancellationToken.IsCancellationRequested) { throw new OperationCanceledException2("Common_OperationCanceled", cancellationToken); } if (IsAddingCompleted) { throw new InvalidOperationException("BlockingCollection_Completed"); } bool flag1 = true; if (m_freeNodes != null) { CancellationTokenSource cancellationTokenSource = null; { try { flag1 = m_freeNodes.Wait(0); if (!flag1 && millisecondsTimeout != 0) { cancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, m_ProducersCancellationTokenSource.Token); flag1 = m_freeNodes.Wait(millisecondsTimeout, cancellationTokenSource.Token); } } catch (OperationCanceledException operationCanceledException) { if (!cancellationToken.IsCancellationRequested) { throw new InvalidOperationException("BlockingCollection_Add_ConcurrentCompleteAdd", operationCanceledException); } throw new OperationCanceledException2("Common_OperationCanceled", cancellationToken); } } } if (!flag1) { return(flag1); } SpinWait spinWait = new SpinWait(); while (true) { int mCurrentAdders = m_currentAdders; if ((mCurrentAdders & -2147483648) != 0) { spinWait.Reset(); while (m_currentAdders != -2147483648) { spinWait.SpinOnce(); } throw new InvalidOperationException("BlockingCollection_Completed"); } if (Interlocked.CompareExchange(ref m_currentAdders, mCurrentAdders + 1, mCurrentAdders) == mCurrentAdders) { break; } spinWait.SpinOnce(); } try { bool flag2 = false; try { cancellationToken.ThrowIfCancellationRequested(); flag2 = m_collection.TryAdd(item); } catch { if (m_freeNodes != null) { m_freeNodes.Release(); } throw; } if (!flag2) { throw new InvalidOperationException("BlockingCollection_Add_Failed"); } m_occupiedNodes.Release(); flag = flag1; } finally { Interlocked.Decrement(ref m_currentAdders); } return(flag); }
private void ProcessNetwork() { Stopwatch time = Stopwatch.StartNew(); int lastPacketId = 0; try { NetworkStream ns = new NetworkStream(Socket); using (ns) { using (MinecraftStream mc = new MinecraftStream(ns)) { SpinWait sw = new SpinWait(); _readerStream = mc; while (!CancellationToken.IsCancellationRequested) { if (time.ElapsedMilliseconds > 5000) { Log.Info($"No messages received. Stopping?"); time.Restart(); } /*SpinWait.SpinUntil(() => ns.DataAvailable || CancellationToken.IsCancellationRequested);*/ if (CancellationToken.IsCancellationRequested) { break; } if (!ns.DataAvailable) { sw.SpinOnce(); continue; } if (TryReadPacket(mc, out lastPacketId)) { time.Restart(); } } } } } catch (Exception ex) { // if (ex is OperationCanceledException) return; // if (ex is EndOfStreamException) return; // if (ex is IOException) return; if (LogExceptions) { Log.Warn( $"Failed to process network (Last packet: 0x{lastPacketId:X2} State: {ConnectionState}): " + ex); } } finally { Disconnected(false); } }
/// <summary> /// Removes the first element from the queue and returns it (or <c>null</c>). /// </summary> /// <param name="blockWhenEmpty"> /// If <c>true</c> and the queue is empty, the calling thread is blocked until /// either an element is enqueued, or <see cref="Stop"/> is called. /// </param> /// <returns> /// <list type="bullet"> /// <item> /// <term>If the queue not empty</term> /// <description>the first element.</description> /// </item> /// <item> /// <term>otherwise, if <paramref name="blockWhenEmpty"/>==<c>false</c> /// or <see cref="Stop"/> has been called</term> /// <description><c>null</c>.</description> /// </item> /// </list> /// </returns> public Event Dequeue(bool blockWhenEmpty) { SpinWait sw = new SpinWait(); do { int cachedRemoveId = _removeId; int cachedAddId = _addId; // Empty case if (cachedRemoveId == cachedAddId) { if (!blockWhenEmpty || _stopped != 0) return null; // Spin a few times to see if something changes if (sw.Count <= spinCount) { sw.SpinOnce(); } else { // Reset to wait for an enqueue _mreAdd.Reset(); // Recheck for an enqueue to avoid a Wait if (cachedRemoveId != _removeId || cachedAddId != _addId) { // Queue is not empty, set the event _mreAdd.Set(); continue; } // Wait for something to happen _mreAdd.Wait(500); } continue; } // Validate that we are the current dequeuer if (Interlocked.CompareExchange(ref _removeId, cachedRemoveId + 1, cachedRemoveId) != cachedRemoveId) continue; // Dequeue our work item Event e; while (!_queue.TryDequeue (out e)) { if (!blockWhenEmpty || _stopped != 0) return null; } return e; } while (true); }
/// <summary> /// The auto receiver action handler. /// </summary> /// <param name="data">The data from the server.</param> private void ReceiveAction(byte[] data) { // Make sure only one thread at a time is adding to the buffer. lock (_lockReceiver) { // Make sure data has arrived. if (data.Length > 0) { // If the upper capacity of the buffer // has been reached then stop writting // until the request buffer gets to the // lower capacity threshold. if (_responseBuffer.IsUpperCapacityPercentage()) { // Create the tasks. Task[] tasks = new Task[1]; Interlocked.Exchange(ref _exitWaitReceiveIndicator, 0); try { // Write to the request stream task. Task readFromStream = Task.Factory.StartNew(() => { // Create a new spin wait. SpinWait sw = new SpinWait(); // Action to perform. while (Interlocked.CompareExchange(ref _exitWaitReceiveIndicator, 0, 1) == 0) { // The NextSpinWillYield property returns true if // calling sw.SpinOnce() will result in yielding the // processor instead of simply spinning. if (sw.NextSpinWillYield) { // If the buffer is below the lower capacity // threshold then exist the spin wait. if (!_responseBuffer.IsLowerCapacityPercentage()) { Interlocked.Exchange(ref _exitWaitReceiveIndicator, 1); } } // Performs a single spin. sw.SpinOnce(); } }); // Assign the listener task. tasks[0] = readFromStream; // Wait for all tasks to complete. Task.WaitAll(tasks); } catch { } // For each task. foreach (Task item in tasks) { try { // Release the resources. item.Dispose(); } catch { } } tasks = null; } // Write to the response stream. _responseStream.WriteToStream(data, 0, data.Length); } } // Make sure data has arrived. if (data.Length > 0) { // Make sure the context exists. if (_context != null) { // If the data available handler has been set // then send a trigger indicating that // data is available. if (_context.OnReceivedHandler != null) { // If not in async mode. if (!_context.IsAsyncMode) { // Allow an active context. if (Interlocked.CompareExchange(ref _isContextActive, 1, 0) == 0) { // Set the active context indicator to true // no other context can start. Interlocked.Exchange(ref _isContextActive, 1); // Received the request from the client. // Send the message context. Receiver(); } } } } } }
internal void RemoveCallback(CancellationTokenRegistration tokenReg) { if (!canceled) { lock (syncRoot) { if (!canceled) { callbacks.Remove (tokenReg); return; } } } SpinWait sw = new SpinWait (); while (!processed) sw.SpinOnce (); }
/// <summary> /// Spins until the specified condition is satisfied or until the specified timeout is expired. /// </summary> /// <param name="condition">A delegate to be executed over and over until it returns true.</param> /// <param name="millisecondsTimeout"> /// The number of milliseconds to wait, or /// <see /// cref="System.Threading.Timeout.Infinite" /> /// (-1) to wait indefinitely. /// </param> /// <returns>True if the condition is satisfied within the timeout; otherwise, false</returns> /// <exception cref="ArgumentNullException">The <paramref name="condition" /> argument is null.</exception> /// <exception cref="T:System.ArgumentOutOfRangeException"> /// <paramref name="millisecondsTimeout" /> is a /// negative number other than -1, which represents an infinite time-out. /// </exception> public static bool SpinUntil(Func<bool> condition, int millisecondsTimeout) { if (millisecondsTimeout < Timeout.Infinite) { throw new ArgumentOutOfRangeException("millisecondsTimeout", millisecondsTimeout, "SpinWait_SpinUntil_TimeoutWrong"); } if (condition == null) { throw new ArgumentNullException("condition", "SpinWait_SpinUntil_ArgumentNull"); } long startTicks = 0; ; if (millisecondsTimeout != 0 && millisecondsTimeout != Timeout.Infinite) { startTicks = DateTime.UtcNow.Ticks; } var spinner = new SpinWait(); while (!condition()) { if (millisecondsTimeout == 0) { return false; } spinner.SpinOnce(); if (millisecondsTimeout != Timeout.Infinite && spinner.NextSpinWillYield) { if (millisecondsTimeout <= (DateTime.UtcNow.Ticks - startTicks)/TimeSpan.TicksPerMillisecond) { return false; } } } return true; }
/// <summary> /// This method is the meat of the lock-free aggregation logic. /// </summary> /// <param name="metricValue">Already filtered and conveted value to be tracked. /// We know that the value is not Double.NaN and not null and it passed trought any filters.</param> private void TrackFilteredConvertedValue(TBufferedValue metricValue) { // Get reference to the current buffer: MetricValuesBufferBase <TBufferedValue> buffer = _metricValuesBuffer; // Get the index at which to store metricValue into the buffer: int index = buffer.IncWriteIndex(); // Check to see whether we are past the end of the buffer. // If we are, it means that some *other* thread hit exactly the end (wrote the last value that fits into the buffer) and is currently flushing. // If we are, we will spin and wait. if (index >= buffer.Capacity) { #if DEBUG int startMillis = Environment.TickCount; #endif #pragma warning disable SA1129 // Do not use default value type constructor var spinWait = new SpinWait(); #pragma warning restore SA1129 // Do not use default value type constructor // It could be that the thread that was flushing is done and has updated the buffer pointer. // We refresh our local reference and see if we now have a valid index into the buffer. buffer = _metricValuesBuffer; index = buffer.IncWriteIndex(); while (index >= buffer.Capacity) { // Still not valid index into the buffer. Spin and try again. spinWait.SpinOnce(); #if DEBUG unchecked { Interlocked.Increment(ref s_countBufferWaitSpinCycles); } #endif if (spinWait.Count % 100 == 0) { // In tests (including stress tests) we always finished wating before 100 cycles. // However, this is a protection against en extreme case on a slow machine. // We will back off and sleep for a few millisecs to give the machine a chance to finish current tasks. Task.Delay(10).ConfigureAwait(continueOnCapturedContext: false).GetAwaiter().GetResult(); } // Check to see whether the thread that was flushing is done and has updated the buffer pointer. // We refresh our local reference and see if we now have a valid index into the buffer. buffer = _metricValuesBuffer; index = buffer.IncWriteIndex(); } #if DEBUG unchecked { int periodMillis = Environment.TickCount - startMillis; int currentSpinMillis = s_timeBufferWaitSpinMillis; int prevSpinMillis = Interlocked.CompareExchange(ref s_timeBufferWaitSpinMillis, currentSpinMillis + periodMillis, currentSpinMillis); while (prevSpinMillis != currentSpinMillis) { currentSpinMillis = s_timeBufferWaitSpinMillis; prevSpinMillis = Interlocked.CompareExchange(ref s_timeBufferWaitSpinMillis, currentSpinMillis + periodMillis, currentSpinMillis); } Interlocked.Increment(ref s_countBufferWaitSpinEvents); } #endif } // Ok, so now we know that (0 <= index = buffer.Capacity). Write the value to the buffer: buffer.WriteValue(index, metricValue); // If this was the last value that fits into the buffer, we must flush the buffer: if (index == buffer.Capacity - 1) { // Before we begin flushing (which is can take time), we update the _metricValuesBuffer to a fresh buffer that is ready to take values. // That way threads do notneed to spin and wait until we flush and can begin writing values. // We try to recycle a previous buffer to lower stress on GC and to lower Gen-2 heap fragmentation. // The lifetime of an buffer can easily be a minute or so and then it can get into Gen-2 GC heap. // If we then, keep throwing such buffers away we can fragment the Gen-2 heap. To avoid this we employ // a simple form of best-effort object pooling. // Get buffer from pool and reset the pool: MetricValuesBufferBase <TBufferedValue> newBufer = Interlocked.Exchange(ref _metricValuesBufferRecycle, null); if (newBufer != null) { // If we were succesful in getting a recycled buffer from the pool, we will try to use it as the new buffer. // If we successfully the the recycled buffer to be the new buffer, we will reset it to prepare for data. // Otherwise we will just throw it away. MetricValuesBufferBase <TBufferedValue> prevBuffer = Interlocked.CompareExchange(ref _metricValuesBuffer, newBufer, buffer); if (prevBuffer == buffer) { newBufer.ResetIndices(); } } else { // If we were succesful in getting a recycled buffer from the pool, we will create a new one. newBufer = InvokeMetricValuesBufferFactory(); Interlocked.CompareExchange(ref _metricValuesBuffer, newBufer, buffer); } // Ok, now we have either set a new buffer that is ready to be used, or we have determined using CompareExchange // that another thread set a new buffer and we do not need to do it here. // Now we can actually flush the buffer: UpdateAggregate(buffer); // The buffer is now flushed. If the slot for the best-effor object pooling is free, use it: Interlocked.CompareExchange(ref _metricValuesBufferRecycle, buffer, null); } }
/// <summary> /// Processes all synchronous events that must take place before the next time loop for the algorithm /// </summary> public virtual void ProcessSynchronousEvents() { // how to do synchronous market orders for real brokerages? // in backtesting we need to wait for orders to be removed from the queue and finished processing if (!_algorithm.LiveMode) { var spinWait = new SpinWait(); while (!_orderRequestQueue.IsEmpty) { // spin wait until the queue is empty spinWait.SpinOnce(); } // now wait for completed processing to signal _processingCompletedEvent.Wait(); return; } Log.Debug("BrokerageTransactionHandler.ProcessSynchronousEvents(): Enter"); // every morning flip this switch back if (_syncedLiveBrokerageCashToday && DateTime.Now.Date != LastSyncDate) { _syncedLiveBrokerageCashToday = false; } // we want to sync up our cash balance before market open if (_algorithm.LiveMode && !_syncedLiveBrokerageCashToday && DateTime.Now.TimeOfDay >= _liveBrokerageCashSyncTime) { try { // only perform cash syncs if we haven't had a fill for at least 10 seconds if (TimeSinceLastFill > TimeSpan.FromSeconds(10)) { PerformCashSync(); } } catch (Exception err) { Log.Error(err, "Updating cash balances"); } } // we want to remove orders older than 10k records, but only in live mode const int maxOrdersToKeep = 10000; if (_orders.Count < maxOrdersToKeep + 1) { Log.Debug("BrokerageTransactionHandler.ProcessSynchronousEvents(): Exit"); return; } int max = _orders.Max(x => x.Key); int lowestOrderIdToKeep = max - maxOrdersToKeep; foreach (var item in _orders.Where(x => x.Key <= lowestOrderIdToKeep)) { Order value; OrderTicket ticket; _orders.TryRemove(item.Key, out value); _orderTickets.TryRemove(item.Key, out ticket); } Log.Debug("BrokerageTransactionHandler.ProcessSynchronousEvents(): Exit"); }
/// <summary> /// Processes all synchronous events that must take place before the next time loop for the algorithm /// </summary> public virtual void ProcessSynchronousEvents() { // how to do synchronous market orders for real brokerages? // in backtesting we need to wait for orders to be removed from the queue and finished processing if (!_algorithm.LiveMode) { var spinWait = new SpinWait(); while (!_orderRequestQueue.IsEmpty) { // spin wait until the queue is empty spinWait.SpinOnce(); } // now wait for completed processing to signal _processingCompletedEvent.Wait(); return; } Log.Debug("BrokerageTransactionHandler.ProcessSynchronousEvents(): Enter"); // every morning flip this switch back if (_syncedLiveBrokerageCashToday && DateTime.Now.Date != LastSyncDate) { _syncedLiveBrokerageCashToday = false; } // we want to sync up our cash balance before market open if (_algorithm.LiveMode && !_syncedLiveBrokerageCashToday && DateTime.Now.TimeOfDay >= _liveBrokerageCashSyncTime) { try { // only perform cash syncs if we haven't had a fill for at least 10 seconds if (TimeSinceLastFill > TimeSpan.FromSeconds(10)) { PerformCashSync(); } } catch (Exception err) { Log.Error(err, "Updating cash balances"); } } // we want to remove orders older than 10k records, but only in live mode const int maxOrdersToKeep = 10000; if (_orders.Count < maxOrdersToKeep + 1) { Log.Debug("BrokerageTransactionHandler.ProcessSynchronousEvents(): Exit"); return; } int max = _orders.Max(x => x.Key); int lowestOrderIdToKeep = max - maxOrdersToKeep; foreach (var item in _orders.Where(x => x.Key <= lowestOrderIdToKeep)) { Order value; OrderTicket ticket; _orders.TryRemove(item.Key, out value); _orderTickets.TryRemove(item.Key, out ticket); } Log.Debug("BrokerageTransactionHandler.ProcessSynchronousEvents(): Exit"); }
/// <summary> /// Dequeue a WorkItem for processing /// </summary> /// <returns>A WorkItem or null if the queue has stopped</returns> public WorkItem Dequeue() { SpinWait sw = new SpinWait(); do { WorkItemQueueState cachedState = State; if (cachedState == WorkItemQueueState.Stopped) { return(null); // Tell worker to terminate } int cachedRemoveId = _removeId; int cachedAddId = _addId; // Empty case (or paused) if (cachedRemoveId == cachedAddId || cachedState == WorkItemQueueState.Paused) { // Spin a few times to see if something changes if (sw.Count <= spinCount) { sw.SpinOnce(); } else { // Reset to wait for an enqueue _mreAdd.Reset(); // Recheck for an enqueue to avoid a Wait if ((cachedRemoveId != _removeId || cachedAddId != _addId) && cachedState != WorkItemQueueState.Paused) { // Queue is not empty, set the event _mreAdd.Set(); continue; } // Wait for something to happen _mreAdd.Wait(500); } continue; } // Validate that we are the current dequeuer if (Interlocked.CompareExchange(ref _removeId, cachedRemoveId + 1, cachedRemoveId) != cachedRemoveId) { continue; } // Dequeue our work item WorkItem work; while (!_innerQueue.TryDequeue(out work)) { } ; // Add to items processed using CAS Interlocked.Increment(ref _itemsProcessed); return(work); } while (true); }
// Helper method to avoid repeating Break() logic between ParallelState64 and ParallelState64<TLocal> internal static void Break(long iteration, ParallelLoopStateFlags64 pflags) { int oldValue = ParallelLoopStateFlags.PLS_NONE; // Attempt to change state from "not stopped or broken or canceled or exceptional" to "broken". if (!pflags.AtomicLoopStateUpdate(ParallelLoopStateFlags.PLS_BROKEN, ParallelLoopStateFlags.PLS_STOPPED | ParallelLoopStateFlags.PLS_EXCEPTIONAL | ParallelLoopStateFlags.PLS_CANCELED, ref oldValue)) { // If we were already stopped, we have a problem if ((oldValue & ParallelLoopStateFlags.PLS_STOPPED) != 0) { throw new InvalidOperationException( Environment.GetResourceString("ParallelState_Break_InvalidOperationException_BreakAfterStop")); } else { // Apparently we previously got cancelled or became exceptional. No action necessary return; } } // replace shared LowestBreakIteration with CurrentIteration, but only if CurrentIteration // is less than LowestBreakIteration. long oldLBI = pflags.LowestBreakIteration; if (iteration < oldLBI) { SpinWait wait = new SpinWait(); while (Interlocked.CompareExchange( ref pflags.m_lowestBreakIteration, iteration, oldLBI) != oldLBI) { wait.SpinOnce(); oldLBI = pflags.LowestBreakIteration; if (iteration > oldLBI) break; } } }
/// <summary> /// Locks the file specified at location <see cref="FilePath"/>. /// </summary> /// <returns>The file lock use that can be revoked by disposing it.</returns> public FileLockUse WaitUntilAcquired() { var lockId = getLockId(); Trace.WriteLine($"{CurrentThreadWithLockIdPrefix(lockId)} Begin locking file {FilePath}.", TraceCategory); SpinWait spinWait = new SpinWait(); while (true) { var currentLocksInUse = locksInUse; var desiredLocksInUse = currentLocksInUse + 1; var currentFileLockerState = fileLockerState; if (currentFileLockerState.IsErroneous()) { if (EnableConcurrentRethrow) { Trace.WriteLine($"{CurrentThreadWithLockIdPrefix(lockId)} Error from previous lock will be rethrown.", TraceCategory); throw currentFileLockerState !.Error !; } // Imagine stair steps where each stair step is Lock(): // Thread #0 Lock #0 -> Incremented to 1 -> Exception occured. // Thread #1 Lock #1 -> Incremented to 2. Recognozes exception in #0 because #0 not yet entered Unlock(). // Thread #2 Lock #2 -> Incremented to 3. Recognizes excetion in #1 because #0 not yet entered Unlock(). // Thread #3 Lock #3 -> Incremented to 1. Lock was successful. // We want Lock #1 and Lock #2 to retry their Lock(): // Thread #1 Lock #1 -> Incremented to 2. Lock was successful. // Thread #2 Lock #2 -> Incremented to 3. Lock was successful. currentFileLockerState !.ErrorUnlockDone !.WaitOne(); Trace.WriteLine($"{CurrentThreadWithLockIdPrefix(lockId)} Retry lock due to previously failed lock.", TraceCategory); continue; } // If it is the initial lock, then we expect file stream being null. // If it is not the initial lock, we expect the stream being not null. else if ((currentLocksInUse == 0 && currentFileLockerState != null) || (currentLocksInUse != 0 && currentFileLockerState == null)) { spinWait.SpinOnce(); continue; } else { if (currentLocksInUse != Interlocked.CompareExchange(ref locksInUse, desiredLocksInUse, currentLocksInUse)) { continue; } // The above conditions met, so if it is the initial lock, then we want // to acquire the lock. if (desiredLocksInUse == 1) { try { var fileStream = LockFileApi.Default.WaitUntilAcquired(FilePath, TimeoutInMilliseconds, fileMode: FileMode, fileAccess: FileAccess, fileShare: FileShare) !; currentFileLockerState = new FileLockContext(this, decreaseLockUseLocker, fileStream); fileLockerState = currentFileLockerState; Trace.WriteLine($"{CurrentThreadWithLockIdPrefix(lockId)} File {FilePath} locked by file locker.", TraceCategory); } catch (Exception error) { var errorUnlockDone = new ManualResetEvent(false); currentFileLockerState = new FileLockContext(this, decreaseLockUseLocker, error, errorUnlockDone); fileLockerState = currentFileLockerState; Unlock(lockId); // After we processed Unlock(), we can surpass these locks // who could be dependent on state assigment of this Lock(). currentFileLockerState.ErrorUnlockDone !.Set(); throw; } } else { Trace.WriteLine($"{CurrentThreadWithLockIdPrefix(lockId)} File {FilePath} locked {desiredLocksInUse} time(s) concurrently by file locker. {fileStreamHasBeenLockedString(currentFileLockerState!.FileStream!)}", TraceCategory); } } var fileLockContract = new FileLockUse(currentFileLockerState, lockId); return(fileLockContract); } }
public bool Wait(int millisecondsTimeout, CancellationToken cancellationToken) { if (millisecondsTimeout < -1) throw new ArgumentOutOfRangeException("millisecondsTimeout"); ThrowIfDisposed(); if (!IsSet) { var wait = new SpinWait(); while (!IsSet) { if (wait.Count < spinCount) { wait.SpinOnce(); continue; } break; } cancellationToken.ThrowIfCancellationRequested(); if (IsSet) return true; WaitHandle handle = WaitHandle; if (cancellationToken.CanBeCanceled) { int result = WaitHandle.WaitAny(new[] {handle, cancellationToken.WaitHandle}, millisecondsTimeout, false); if (result == 1) throw new OperationCanceledException(cancellationToken.ToString()); if (result == WaitHandle.WaitTimeout) return false; } else { if (!handle.WaitOne(millisecondsTimeout, false)) return false; } } return true; }
/// <summary> /// Decreases the number of locks in use. If becoming zero, file gets unlocked. /// </summary> internal int DecreaseLockUse(bool decreaseToZero, string?lockId) { lockId = lockId ?? "none"; SpinWait spinWait = new SpinWait(); int desiredLocksInUse; do { var currentLocksInUse = locksInUse; if (0 >= currentLocksInUse) { Trace.WriteLine($"{CurrentThreadWithLockIdPrefix(lockId)} Number of lock remains at 0 because file has been unlocked before. {unlockSourceString(decreaseToZero)}", TraceCategory); return(0); } if (decreaseToZero) { desiredLocksInUse = 0; } else { desiredLocksInUse = currentLocksInUse - 1; } var actualLocksInUse = Interlocked.CompareExchange(ref locksInUse, desiredLocksInUse, currentLocksInUse); if (currentLocksInUse == actualLocksInUse) { break; } spinWait.SpinOnce(); } while (true); string decreasedNumberOfLocksInUseMessage() => $"{CurrentThreadWithLockIdPrefix(lockId)} Number of lock uses is decreased to {desiredLocksInUse}. {unlockSourceString(decreaseToZero)}"; // When no locks are registered, we have to .. if (0 == desiredLocksInUse) { // 1. wait for file stream assignment, FileLockContext?nullState = null; FileLockContext nonNullState = null !; while (true) { nullState = Interlocked.CompareExchange(ref fileLockerState, null, nullState); /* When class scoped file stream is null local file stream will be null too. * => If so, spin once and continue loop. * * When class scoped file stream is not null the local file stream will become * not null too. * => If so, assigned class scoped file streama to to local non null file stream * and continue loop. * * When class scoped file stream is null and local non null file stream is not null * => If so, break loop. */ if (nullState == null && nonNullState is null) { spinWait.SpinOnce(); } else if (nullState == null && !(nonNullState is null)) { break; } else { nonNullState = nullState !; } } // 2. invalidate the file stream. nonNullState.FileStream?.Close(); nonNullState.FileStream?.Dispose(); Trace.WriteLine($"{decreasedNumberOfLocksInUseMessage()}{Environment.NewLine}{CurrentThreadWithLockIdPrefix(lockId)} File {FilePath} unlocked by file locker. {unlockSourceString(decreaseToZero)}", TraceCategory); } else { Trace.WriteLine($"{decreasedNumberOfLocksInUseMessage()}"); } return(desiredLocksInUse); }
/// <summary> /// Send the response data to the client. /// </summary> private void Sender() { // Make sure only one thread at a time is removing from the buffer. lock (_lockSender) { try { // If the upper capacity of the buffer // has been reached then stop writting // until the response buffer gets to the // lower capacity threshold. if (_requestBuffer.IsUpperCapacityPercentage()) { // Create the tasks. Task[] tasks = new Task[1]; Interlocked.Exchange(ref _exitWaitSendIndicator, 0); try { // Write to the response stream task. Task writeToStream = Task.Factory.StartNew(() => { // Create a new spin wait. SpinWait sw = new SpinWait(); // Action to perform. while (Interlocked.CompareExchange(ref _exitWaitSendIndicator, 0, 1) == 0) { // The NextSpinWillYield property returns true if // calling sw.SpinOnce() will result in yielding the // processor instead of simply spinning. if (sw.NextSpinWillYield) { // Send the data to the client until // the lower capacity buffer has been // reached. SendData(); // If the buffer is below the lower capacity // threshold then exist the spin wait. if (!_requestBuffer.IsLowerCapacityPercentage()) { Interlocked.Exchange(ref _exitWaitSendIndicator, 1); } } // Performs a single spin. sw.SpinOnce(); } }); // Assign the listener task. tasks[0] = writeToStream; // Wait for all tasks to complete. Task.WaitAll(tasks); } catch { } // For each task. foreach (Task item in tasks) { try { // Release the resources. item.Dispose(); } catch { } } tasks = null; } // Send the data to the client. SendData(); } catch { } } }
// **** BACKGROUND THREAD **** private void WorkerLoop() { long?elapsedMs = null; var fileNameOnly = Path.GetFileName(_fileName); #if EDITOR_TRACING var sw = new Stopwatch(); #endif try { RazorEditorTrace.TraceLine(RazorResources.FormatTrace_BackgroundThreadStart(fileNameOnly)); EnsureOnThread(); #if DNXCORE50 var spinWait = new SpinWait(); #endif while (!_shutdownToken.IsCancellationRequested) { // Grab the parcel of work to do var parcel = _main.GetParcel(); if (parcel.Changes.Any()) { RazorEditorTrace.TraceLine(RazorResources.FormatTrace_ChangesArrived(fileNameOnly, parcel.Changes.Count)); try { DocumentParseCompleteEventArgs args = null; using (var linkedCancel = CancellationTokenSource.CreateLinkedTokenSource(_shutdownToken, parcel.CancelToken)) { if (!linkedCancel.IsCancellationRequested) { // Collect ALL changes #if EDITOR_TRACING if (_previouslyDiscarded != null && _previouslyDiscarded.Any()) { RazorEditorTrace.TraceLine(RazorResources.Trace_CollectedDiscardedChanges, fileNameOnly, _previouslyDiscarded.Count); } #endif List <TextChange> allChanges; if (_previouslyDiscarded != null) { allChanges = Enumerable.Concat(_previouslyDiscarded, parcel.Changes).ToList(); } else { allChanges = parcel.Changes.ToList(); } var finalChange = allChanges.Last(); #if EDITOR_TRACING sw.Start(); #endif var results = ParseChange(finalChange.NewBuffer, linkedCancel.Token); #if EDITOR_TRACING sw.Stop(); elapsedMs = sw.ElapsedMilliseconds; sw.Reset(); #endif RazorEditorTrace.TraceLine( RazorResources.FormatTrace_ParseComplete( fileNameOnly, elapsedMs.HasValue ? elapsedMs.Value.ToString(CultureInfo.InvariantCulture) : "?")); if (results != null && !linkedCancel.IsCancellationRequested) { // Clear discarded changes list _previouslyDiscarded = null; // Take the current tree and check for differences #if EDITOR_TRACING sw.Start(); #endif var treeStructureChanged = _currentParseTree == null || TreesAreDifferent(_currentParseTree, results.Document, allChanges, parcel.CancelToken); #if EDITOR_TRACING sw.Stop(); elapsedMs = sw.ElapsedMilliseconds; sw.Reset(); #endif _currentParseTree = results.Document; RazorEditorTrace.TraceLine(RazorResources.FormatTrace_TreesCompared( fileNameOnly, elapsedMs.HasValue ? elapsedMs.Value.ToString(CultureInfo.InvariantCulture) : "?", treeStructureChanged)); // Build Arguments args = new DocumentParseCompleteEventArgs() { GeneratorResults = results, SourceChange = finalChange, TreeStructureChanged = treeStructureChanged }; } else { // Parse completed but we were cancelled in the mean time. Add these to the discarded changes set RazorEditorTrace.TraceLine(RazorResources.FormatTrace_ChangesDiscarded(fileNameOnly, allChanges.Count)); _previouslyDiscarded = allChanges; } #if CHECK_TREE if (args != null) { // Rewind the buffer and sanity check the line mappings finalChange.NewBuffer.Position = 0; var lineCount = finalChange.NewBuffer.ReadToEnd().Split(new string[] { Environment.NewLine, "\r", "\n" }, StringSplitOptions.None).Count(); Debug.Assert( !args.GeneratorResults.DesignTimeLineMappings.Any(pair => pair.Value.StartLine > lineCount), "Found a design-time line mapping referring to a line outside the source file!"); Debug.Assert( !args.GeneratorResults.Document.Flatten().Any(span => span.Start.LineIndex > lineCount), "Found a span with a line number outside the source file"); Debug.Assert( !args.GeneratorResults.Document.Flatten().Any(span => span.Start.AbsoluteIndex > parcel.NewBuffer.Length), "Found a span with an absolute offset outside the source file"); } #endif } } if (args != null) { _main.ReturnParcel(args); } } catch (OperationCanceledException) { } } else { RazorEditorTrace.TraceLine(RazorResources.FormatTrace_NoChangesArrived(fileNameOnly)); #if DNXCORE50 // This does the equivalent of thread.yield under the covers. spinWait.SpinOnce(); #else // No Yield in CoreCLR Thread.Yield(); #endif } } } catch (OperationCanceledException) { // Do nothing. Just shut down. } finally { RazorEditorTrace.TraceLine(RazorResources.FormatTrace_BackgroundThreadShutdown(fileNameOnly)); // Clean up main thread resources _main.Dispose(); } }
private void Test(Func<long> generate, int threadCount, int generatedIdCount) { var waitingThreadCount = 0; var starterGun = new ManualResetEvent(false); var results = new long[generatedIdCount]; var threads = Enumerable.Range(0, threadCount).Select(threadNumber => new Thread(() => { // Wait for all threads to be ready Interlocked.Increment(ref waitingThreadCount); starterGun.WaitOne(); for (int i = threadNumber; i < generatedIdCount; i += threadCount) results[i] = generate(); })).ToArray(); foreach (var t in threads) t.Start(); // Wait for all tasks to reach the waiting stage var wait = new SpinWait(); while (waitingThreadCount < threadCount) wait.SpinOnce(); // Start all the threads at the same time starterGun.Set(); foreach (var t in threads) t.Join(); var ids = new HashSet<long>(); foreach (var value in results) { if (!ids.Add(value)) { throw new AssertException("Id " + value + " was generated more than once, in indices " + string.Join(", ", results.Select(Tuple.Create<long, int>).Where(x => x.Item1 == value).Select(x => x.Item2))); } } for (long i = 1; i <= GeneratedIdCount; i++) Assert.True(ids.Contains(i), "Id " + i + " was not generated."); }
private void ProcessMeasurements() { List <IMeasurement> measurements = new List <IMeasurement>((int)(Ticks.ToSeconds(GapThreshold) * m_sampleRate * m_channels * 1.1D)); LittleBinaryValue[] sample; while (Enabled) { try { SpinWait spinner = new SpinWait(); // Determine what time it is now long now = DateTime.UtcNow.Ticks; // Assign a timestamp to the next sample based on its location // in the file relative to the other samples in the file long timestamp = m_startTime + (m_dataIndex * Ticks.PerSecond / m_sampleRate); if (now - timestamp > GapThreshold) { // Reset the start time and delay next transmission in an attempt to catch up m_startTime = now - (m_dataIndex * Ticks.PerSecond / m_sampleRate) + Ticks.FromSeconds(RecoveryDelay); timestamp = now; OnStatusMessage(MessageLevel.Info, "Start time reset."); } // Keep generating measurements until // we catch up to the current time. while (timestamp < now) { sample = m_dataReader.GetNextSample(); // If the sample is null, we've reached the end of the file - close and reopen, // resetting the data index and start time if (sample == null) { m_dataReader.Close(); m_dataReader.Dispose(); m_dataReader = OpenWaveDataReader(); m_dataIndex = 0; m_startTime = timestamp; sample = m_dataReader.GetNextSample(); } // Create new measurements, one for each channel, and add them to the measurements list for (int i = 0; i < m_channels; i++) { measurements.Add(Measurement.Clone(OutputMeasurements[i], sample[i].ConvertToType(TypeCode.Double), timestamp)); } // Update the data index and recalculate the assigned timestamp for the next sample m_dataIndex++; timestamp = m_startTime + (m_dataIndex * Ticks.PerSecond / m_sampleRate); } OnNewMeasurements(measurements); measurements.Clear(); while (DateTime.UtcNow.Ticks - timestamp <= GapThreshold / 100) { // Ahead of schedule -- pause for a moment spinner.SpinOnce(); } } catch (Exception ex) { OnProcessException(MessageLevel.Warning, ex); } } }