public void TestAllThreadWakeUpOnSignalAll() { using (var testInst = new MonitorObject()) { int exitCount = 0; int state = 0; List <Task> tasks = new List <Task>(); for (int i = 0; i < 6; i++) { var task = Task.Run(() => { using (var waiter = testInst.Enter()) { waiter.Wait(_ => { return(Volatile.Read(ref state) > 0); }, (object)null); Interlocked.Increment(ref exitCount); } }); tasks.Add(task); } TimingAssert.AreEqual(10000, 6, () => testInst.WaiterCount); Interlocked.Increment(ref state); testInst.PulseAll(); TimingAssert.AreEqual(10000, 0, () => testInst.WaiterCount); TimingAssert.AreEqual(10000, 6, () => Volatile.Read(ref exitCount)); Task.WaitAll(tasks.ToArray()); } }
/// <summary> /// Removes completed segments /// </summary> /// <param name="allowNotification">Allows to send notification for adders (only when called from background thread)</param> private void Compact(bool allowNotification) { if (_isDisposed) { return; } List <DiskQueueSegmentWrapper <T> > _segmentsToCleanUp = null; bool shouldNotifyWaiters = false; lock (_segmentOperationsLock) { if (_isDisposed) { return; } VerifyConsistency(); shouldNotifyWaiters = allowNotification && _segments.Count >= _maxSegmentCount; MoveHeadToNonCompletedSegment(); // Correct head segment while (_segments.Count > 1 && _headSegment != _segments[0] && _segments[0].IsCompleted) { _segmentsToCleanUp = _segmentsToCleanUp ?? new List <DiskQueueSegmentWrapper <T> >(); _segmentsToCleanUp.Add(_segments.RemoveFirst()); } } if (_segmentsToCleanUp != null) { if (shouldNotifyWaiters) { _addMonitor.PulseAll(); // Segment allocation is now possible } foreach (var segment in _segmentsToCleanUp) { segment.Dispose(DiskQueueSegmentDisposeBehaviour.Delete); } } }
/// <summary> /// Notifies about item addition /// </summary> private void NotifyItemAdded() { Interlocked.Increment(ref _itemCount); _takeMonitor.Pulse(); _peekMonitor.PulseAll(); }