/// <summary> /// LevelingQueue constructor /// </summary> /// <param name="highLevelQueue">High level queue (queue with higher priority)</param> /// <param name="lowLevelQueue">Low level queue (queue with lower priority)</param> /// <param name="addingMode">Adding mode of the queue</param> /// <param name="isBackgroundTransferingEnabled">Is background transfering items from LowLevelQueue to HighLevelQueue enabled</param> public LevelingQueue(IQueue <T> highLevelQueue, IQueue <T> lowLevelQueue, LevelingQueueAddingMode addingMode, bool isBackgroundTransferingEnabled) { if (highLevelQueue == null) { throw new ArgumentNullException(nameof(highLevelQueue)); } if (lowLevelQueue == null) { throw new ArgumentNullException(nameof(lowLevelQueue)); } _highLevelQueue = highLevelQueue; _lowLevelQueue = lowLevelQueue; _addingMode = addingMode; _isBackgroundTransferingEnabled = isBackgroundTransferingEnabled; _addMonitor = new MonitorObject("LevelingQueue.AddMonitor"); _takeMonitor = new MonitorObject("LevelingQueue.TakeMonitor"); _peekMonitor = new MonitorObject("LevelingQueue.PeekMonitor"); _itemCount = highLevelQueue.Count + lowLevelQueue.Count; _isDisposed = false; if (isBackgroundTransferingEnabled) { _backgoundTransfererExclusive = new MutuallyExclusivePrimitive(); if (addingMode == LevelingQueueAddingMode.PreferLiveData) { _backgoundTransfererExclusive.AllowBackgroundGate(); // Allow background transfering from the start } _backgroundTransferer = new DelegateThreadSetManager(1, this.GetType().GetCSName() + "_" + this.GetHashCode().ToString() + " Background Transferer", BackgroundTransferProc); _backgroundTransferer.IsBackground = true; _backgroundTransferer.Start(); } }
// =================== private void RunComplexTest(MutuallyExclusivePrimitive inst, int workCount, int workSpin, int sleepProbability) { Barrier barrier = new Barrier(4); CancellationTokenSource globalCancellation = new CancellationTokenSource(); ManualResetEventSlim alwaysNotSet = new ManualResetEventSlim(false); int workPerformGate1 = 0; int workPerformGate2 = 0; int workCompletedCount = 0; int gate1Executed = 0; int gate2Executed = 0; Action <Random, CancellationToken, int> doWork = (Random rnd, CancellationToken token, int gate) => { try { if (gate == 1) { Interlocked.Increment(ref workPerformGate1); if (Volatile.Read(ref workPerformGate2) != 0) { throw new Exception("Mutual exclusive logic is broken"); } Interlocked.Increment(ref gate1Executed); } else { Interlocked.Increment(ref workPerformGate2); if (Volatile.Read(ref workPerformGate1) != 0) { throw new Exception("Mutual exclusive logic is broken"); } Interlocked.Increment(ref gate2Executed); } if (rnd.Next(sleepProbability) == 0) { alwaysNotSet.Wait(1, token); } else { int spin = rnd.Next(0, workSpin); Thread.SpinWait(spin); } } finally { if (gate == 1) { Interlocked.Decrement(ref workPerformGate1); } else { Interlocked.Decrement(ref workPerformGate2); } } }; Action <int> worker = (int gate) => { var token = globalCancellation.Token; Random rnd = new Random(Environment.TickCount + Thread.CurrentThread.ManagedThreadId); barrier.SignalAndWait(); while (!token.IsCancellationRequested) { try { using (var guard = gate == 1 ? inst.EnterMain(Timeout.Infinite, token) : inst.EnterBackground(Timeout.Infinite, token)) { using (var linked = CancellationTokenSource.CreateLinkedTokenSource(token, guard.Token)) { doWork(rnd, token, gate); } } int spin = rnd.Next(0, workSpin); Thread.SpinWait(spin); } catch (OperationCanceledException) { } int localWorkCompl = Interlocked.Increment(ref workCompletedCount); if (localWorkCompl > workCount) { globalCancellation.Cancel(); } } }; Action switcher = () => { var token = globalCancellation.Token; Random rnd = new Random(Environment.TickCount + Thread.CurrentThread.ManagedThreadId); barrier.SignalAndWait(); while (!token.IsCancellationRequested) { int sleep = rnd.Next(workSpin); Thread.Sleep(sleep); inst.AllowBackgroundGate(); sleep = rnd.Next(workSpin); Thread.Sleep(sleep); inst.DisallowBackgroundGate(); } }; Task workerThread1 = Task.Factory.StartNew(() => worker(1), TaskCreationOptions.LongRunning); Task workerThread2 = Task.Factory.StartNew(() => worker(2), TaskCreationOptions.LongRunning); Task workerThread3 = Task.Factory.StartNew(() => worker(2), TaskCreationOptions.LongRunning); Task switcherThread = Task.Factory.StartNew(() => switcher(), TaskCreationOptions.LongRunning); Task.WaitAll(workerThread1, workerThread2, workerThread3, switcherThread); Assert.IsTrue(gate1Executed > 0); Assert.IsTrue(gate2Executed > 0); }