public void Enqueue(T item) { if (_size >= _items.Length) { var temp = _items; _items = new IndexedItem[_items.Length * 2]; Array.Copy(temp, _items, temp.Length); } var index = _size++; _items[index] = new IndexedItem { Value = item, Id = Interlocked2.Increment(ref _count) }; Percolate(index); }
private static void MultipleProducerConsumer_AllItemsTransferred(int producers, int consumers, int itemsPerProducer) { var cq = new ConcurrentQueue <int>(); var tasks = new List <Task>(); int totalItems = producers * itemsPerProducer; int remainingItems = totalItems; int sum = 0; for (int i = 0; i < consumers; i++) { tasks.Add(Task.Factory.StartNew(() => { while (Volatile.Read(ref remainingItems) > 0) { int item; if (cq.TryDequeue(out item)) { Interlocked2.Add(ref sum, item); Interlocked.Decrement(ref remainingItems); } } }, CancellationToken.None, TaskCreationOptions.LongRunning, TaskScheduler.Default)); } for (int i = 0; i < producers; i++) { tasks.Add(Task.Factory.StartNew(() => { for (int item = 1; item <= itemsPerProducer; item++) { cq.Enqueue(item); } }, CancellationToken.None, TaskCreationOptions.LongRunning, TaskScheduler.Default)); } Task.WaitAll(tasks.ToArray()); Assert.AreEqual(producers * (itemsPerProducer * (itemsPerProducer + 1) / 2), sum); }
/// <summary> /// Acquires the lock in shared mode, blocking /// if necessary. /// </summary> /// <remarks> /// Exclusive acquires are given precedence over shared /// acquires. /// </remarks> public void AcquireShared() { int value; int i = 0; #if ENABLE_STATISTICS Interlocked.Increment(ref _acqShrdCount); #endif while (true) { value = _value; // Case 1: lock not owned AND no exclusive waiter is waking up AND // there are no shared owners AND there are no exclusive waiters if ((value & ( LockOwned | (LockSharedOwnersMask << LockSharedOwnersShift) | ExclusiveMask )) == 0) { if (Interlocked.CompareExchange( ref _value, value + LockOwned + LockSharedOwnersIncrement, value ) == value) { break; } } // Case 2: lock is owned AND no exclusive waiter is waking up AND // there are shared owners AND there are no exclusive waiters else if ( (value & LockOwned) != 0 && ((value >> LockSharedOwnersShift) & LockSharedOwnersMask) != 0 && (value & ExclusiveMask) == 0 ) { if (Interlocked.CompareExchange( ref _value, value + LockSharedOwnersIncrement, value ) == value) { break; } } // Other cases. else if (i >= SpinCount) { #if DEFER_EVENT_CREATION this.EnsureEventCreated(ref _sharedWakeEvent); #endif if (Interlocked.CompareExchange( ref _value, value + LockSharedWaitersIncrement, value ) == value) { #if ENABLE_STATISTICS Interlocked.Increment(ref _acqShrdSlpCount); int shrdWtrsCount = (value >> LockSharedWaitersShift) & LockSharedWaitersMask; Interlocked2.Set( ref _peakShrdWtrsCount, (p) => p < shrdWtrsCount, (p) => shrdWtrsCount ); #endif // Go to sleep. if (NativeMethods.WaitForSingleObject( _sharedWakeEvent, Timeout.Infinite ) != NativeMethods.WaitObject0) { UtilsBreak("Utils.MsgFailedToWaitIndefinitely"); } // Go back and try again. continue; } } #if ENABLE_STATISTICS Interlocked.Increment(ref _acqShrdContCount); #endif i++; } }
/// <summary> /// Acquires the lock in exclusive mode, blocking /// if necessary. /// </summary> /// <remarks> /// Exclusive acquires are given precedence over shared /// acquires. /// </remarks> public void AcquireExclusive() { int value; int i = 0; #if ENABLE_STATISTICS Interlocked.Increment(ref _acqExclCount); #endif while (true) { value = _value; // Case 1: lock not owned AND an exclusive waiter is not waking up. // Here we don't have to check if there are exclusive waiters, because // if there are the lock would be owned, and we are checking that anyway. if ((value & (LockOwned | LockExclusiveWaking)) == 0) { #if RIGOROUS_CHECKS System.Diagnostics.Trace.Assert(((value >> LockSharedOwnersShift) & LockSharedOwnersMask) == 0); System.Diagnostics.Trace.Assert(((value >> LockExclusiveWaitersShift) & LockExclusiveWaitersMask) == 0); #endif if (Interlocked.CompareExchange( ref _value, value + LockOwned, value ) == value) { break; } } // Case 2: lock owned OR lock not owned and an exclusive waiter is waking up. // The second case means an exclusive waiter has just been woken up and is // going to acquire the lock. We have to go to sleep to make sure we don't // steal the lock. else if (i >= SpinCount) { #if DEFER_EVENT_CREATION // This call must go *before* the next operation. Otherwise, // we will have a race condition between potential releasers // and us. this.EnsureEventCreated(ref _exclusiveWakeEvent); #endif if (Interlocked.CompareExchange( ref _value, value + LockExclusiveWaitersIncrement, value ) == value) { #if ENABLE_STATISTICS Interlocked.Increment(ref _acqExclSlpCount); int exclWtrsCount = (value >> LockExclusiveWaitersShift) & LockExclusiveWaitersMask; Interlocked2.Set( ref _peakExclWtrsCount, (p) => p < exclWtrsCount, (p) => exclWtrsCount ); #endif // Go to sleep. if (NativeMethods.WaitForSingleObject( _exclusiveWakeEvent, Timeout.Infinite ) != NativeMethods.WaitObject0) { UtilsBreak("Utils.MsgFailedToWaitIndefinitely"); } // Acquire the lock. // At this point *no one* should be able to steal the lock from us. do { value = _value; #if RIGOROUS_CHECKS System.Diagnostics.Trace.Assert((value & LockOwned) == 0); System.Diagnostics.Trace.Assert((value & LockExclusiveWaking) != 0); #endif } while(Interlocked.CompareExchange( ref _value, value + LockOwned - LockExclusiveWaking, value ) != value); break; } } #if ENABLE_STATISTICS Interlocked.Increment(ref _acqExclContCount); #endif i++; } }