public void TestAllowBackgroundGate() { using (var inst = new MutuallyExclusivePrimitive()) { using (var guard = inst.EnterMain(0, default(CancellationToken))) { Assert.IsTrue(guard.IsAcquired); } using (var guard = inst.EnterBackground(0, default(CancellationToken))) { Assert.IsFalse(guard.IsAcquired); } inst.AllowBackgroundGate(); using (var guard = inst.EnterMain(0, default(CancellationToken))) { Assert.IsTrue(guard.IsAcquired); } using (var guard = inst.EnterBackground(0, default(CancellationToken))) { Assert.IsTrue(guard.IsAcquired); } } }
/// <summary> /// Adds new item to the queue, even when the bounded capacity reached /// </summary> /// <param name="item">New item</param> public override void AddForced(T item) { CheckDisposed(); if (_addingMode == LevelingQueueAddingMode.PreferLiveData) { if (!_highLevelQueue.TryAdd(item, 0, default(CancellationToken))) { _lowLevelQueue.AddForced(item); if (_isBackgroundTransferingEnabled) { _backgoundTransfererExclusive.AllowBackgroundGate(); // Allow background transfering } } } else { bool addedToHighLevelQueue = false; if (_isBackgroundTransferingEnabled) { if (_lowLevelQueue.IsEmpty) { // Only in exclusive mode using (var gateGuard = _backgoundTransfererExclusive.EnterMain(Timeout.Infinite, default(CancellationToken))) // This should happen fast { TurboContract.Assert(gateGuard.IsAcquired, conditionString: "gateGuard.IsAcquired"); addedToHighLevelQueue = _lowLevelQueue.IsEmpty && _highLevelQueue.TryAdd(item, 0, default(CancellationToken)); } } } else { addedToHighLevelQueue = _lowLevelQueue.IsEmpty && _highLevelQueue.TryAdd(item, 0, default(CancellationToken)); } if (!addedToHighLevelQueue) { _lowLevelQueue.AddForced(item); if (_isBackgroundTransferingEnabled) { _backgoundTransfererExclusive.AllowBackgroundGate(); // Allow background transfering } } } NotifyItemAdded(); }
public void TestMutuallExclusiveWaits() { using (var inst = new MutuallyExclusivePrimitive()) { using (var guard = inst.EnterMain(0, default(CancellationToken))) { Assert.IsTrue(guard.IsAcquired); inst.AllowBackgroundGate(); using (var guard2 = inst.EnterBackground(0, default(CancellationToken))) { Assert.IsFalse(guard2.IsAcquired); } var task = Task.Run(() => { using (var guard2 = inst.EnterBackground(60000, default(CancellationToken))) { Assert.IsTrue(guard2.IsAcquired); } }); guard.Dispose(); task.Wait(); } } }
public void ForegroundCancellBackgroundTest() { using (var inst = new MutuallyExclusivePrimitive()) { inst.AllowBackgroundGate(); using (var guard = inst.EnterBackground(0, default(CancellationToken))) { Assert.IsTrue(guard.IsAcquired); inst.AllowBackgroundGate(); using (var guard2 = inst.EnterMain(0, default(CancellationToken))) { Assert.IsFalse(guard2.IsAcquired); Assert.IsTrue(guard.Token.IsCancellationRequested); } } } }
public void TestGateOpenAndEnter() { const int AttemptCount = 500000; using (var inst = new MutuallyExclusivePrimitive()) { inst.AllowBackgroundGate(); using (var outerGuard = inst.EnterBackground(0, default(CancellationToken))) { Assert.IsTrue(outerGuard.IsAcquired); Barrier bar = new Barrier(2); int entered = 0; var task = Task.Run(() => { bar.SignalAndWait(); for (int i = 0; i < AttemptCount; i++) { using (var guard = inst.EnterMain(60000, default(CancellationToken))) { Assert.IsTrue(guard.IsAcquired); Interlocked.Increment(ref entered); } } }); bar.SignalAndWait(); Thread.Sleep(100); outerGuard.Dispose(); while (Volatile.Read(ref entered) < AttemptCount) { using (var ggg = inst.EnterBackground(0, default(CancellationToken))) { } } Assert.AreEqual(AttemptCount, Volatile.Read(ref entered)); task.Wait(); } } }
// =================== 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); }