/// <summary> /// Attempts to remove batch from the head of the queue /// </summary> /// <param name="segment">Removed batch</param> /// <returns>True if the batch was removed</returns> internal bool TryDequeue(out BatchingQueueSegment <T> segment) { SpinWait sw = new SpinWait(); while (true) { BatchingQueueSegment <T> head = _head; if (head == _tail) { segment = null; return(false); } Debug.Assert(head.Next != null); if (Interlocked.CompareExchange(ref _head, head.Next, head) == head) { SpinWait completionSw = new SpinWait(); while (!head.IsNotInWork) { completionSw.SpinOnce(); } Interlocked.Add(ref _itemsCount, -head.Count); segment = head; return(true); } sw.SpinOnceNoSleep(); } }
public void TestSpinWaitSpins() { SpinWait sw = new SpinWait(); for (int i = 0; i < 10; i++) { Assert.AreEqual(i, sw.Count); sw.SpinOnceNoSleep(); } }
public void TestSpinWaitNotSleep() { SpinWait sw = new SpinWait(); Stopwatch stopwatch = Stopwatch.StartNew(); for (int i = 0; i < 100; i++) { sw.SpinOnceNoSleep(); } stopwatch.Stop(); Assert.IsTrue(stopwatch.ElapsedMilliseconds <= 5); }
private bool TryAcquireItemCount() { SpinWait sw = new SpinWait(); int itemCount = _itemCount; while (itemCount > 0 && Interlocked.CompareExchange(ref _itemCount, itemCount - 1, itemCount) != itemCount) { sw.SpinOnceNoSleep(); itemCount = _itemCount; } return(itemCount > 0); }
private bool TryAcquireFillCount() { SpinWait sw = new SpinWait(); int fillCount = _fillCount; while (fillCount < _capacity && Interlocked.CompareExchange(ref _fillCount, fillCount + 1, fillCount) != fillCount) { sw.SpinOnceNoSleep(); fillCount = _fillCount; } return(fillCount < _capacity); }
/// <summary> /// Reads 'head' and 'tail' atomically /// </summary> /// <param name="head">Current head of the queue</param> /// <param name="tail">Current tail of the queue</param> private void GetHeadTailAtomic(out BatchingQueueSegment <T> head, out BatchingQueueSegment <T> tail) { head = _head; tail = _tail; SpinWait sw = new SpinWait(); while (head != _head || tail != _tail) { sw.SpinOnceNoSleep(); head = _head; tail = _tail; } }
private void AddCore(PoolElementWrapper <T> element) { SpinWait sw = new SpinWait(); var headIndexOp = _headIndexOp; element.NextIndex = GetHeadIndex(headIndexOp); while (Interlocked.CompareExchange(ref _headIndexOp, Repack(element.ThisIndex, headIndexOp), headIndexOp) != headIndexOp) { sw.SpinOnceNoSleep(); headIndexOp = _headIndexOp; element.NextIndex = GetHeadIndex(headIndexOp); } }
private bool TryTakeLockFree() { SpinWait spin = new SpinWait(); int currentCountLocFree = _currentCountLockFree; while (currentCountLocFree > 0) { if (Interlocked.CompareExchange(ref _currentCountLockFree, currentCountLocFree - 1, currentCountLocFree) == currentCountLocFree) { return(true); } spin.SpinOnceNoSleep(); currentCountLocFree = _currentCountLockFree; } return(false); }
private bool TryTakeCore(out PoolElementWrapper <T> element) { SpinWait sw = new SpinWait(); var headIndexOp = _headIndexOp; while (GetHeadIndex(headIndexOp) >= 0) { var headElem = _dataArray.GetItemSafe(GetHeadIndex(headIndexOp)); if (headElem != null && Interlocked.CompareExchange(ref _headIndexOp, Repack(headElem.NextIndex, headIndexOp), headIndexOp) == headIndexOp) { element = headElem; element.NextIndex = -1; return(true); } sw.SpinOnceNoSleep(); headIndexOp = _headIndexOp; } element = null; return(false); }
/// <summary> /// Attempts to create the next BatchingQueueSegment in the Linked List structure /// </summary> /// <returns>true - segments created and can be read through <see cref="Next"/> property, false - no new segment created due to already created next segment</returns> internal bool Grow() { int reservedIndexWithFinalizationMark = _reservedIndexWithFinalizationMark; if (IsSegmentFinalized(reservedIndexWithFinalizationMark)) { return(false); } bool result = false; var newSegment = _preallocatedNext ?? new BatchingQueueSegment <T>(Capacity, unchecked (_batchId + 1)); SpinWait sw = new SpinWait(); try { } finally { reservedIndexWithFinalizationMark = _reservedIndexWithFinalizationMark; while (!IsSegmentFinalized(reservedIndexWithFinalizationMark)) { if (Interlocked.CompareExchange(ref _reservedIndexWithFinalizationMark, SetSegmentFinalized(reservedIndexWithFinalizationMark), reservedIndexWithFinalizationMark) == reservedIndexWithFinalizationMark) { result = Interlocked.CompareExchange(ref _next, newSegment, null) == null; TurboContract.Assert(result, "New segment update failed"); break; } sw.SpinOnceNoSleep(); reservedIndexWithFinalizationMark = _reservedIndexWithFinalizationMark; } } if (result && Capacity >= SegmentPreallocationCapacityThreshold) { newSegment.PreallocateNextSegment(); } return(result); }
/// <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.SpinOnceNoSleep(); 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; } } } }