private void CheckPipelineState(int size, int capacity, InterlockedFlag capacityReached) { Assert.IsTrue(size >= 0); Assert.IsTrue(capacity > 0); // a understood flaw of the current algorithm is that the capacity can be exceeded by one item. we've decided that this is acceptable and we allow it to happen. Assert.IsTrue(size <= capacity, string.Format("size ({0}) must be less than the capacity ({1})", size, capacity)); if (capacityReached != null && size == capacity) { capacityReached.TrySet(); } }
private ProducerObserver(ILogger logger, IGrainFactory grainFactory) { _logger = logger; _observer = null; _timers = new Dictionary <IDisposable, TimerState>(); _itemsProduced = 0; _expectedItemsProduced = 0; _streamId = default(Guid); _providerName = null; _cleanedUpFlag = new InterlockedFlag(); _observerDisposedYet = false; _grainFactory = grainFactory; }
private async Task AsyncPipelineBlackBoxConsistencyTest(int workerCount) { if (workerCount < 1) { throw new ArgumentOutOfRangeException("You must specify at least one worker.", "workerCount"); } int loopCount = _iterationCount / workerCount; const double variance = 0.1; int expectedTasksCompleted = loopCount * workerCount; var delayLength = TimeSpan.FromSeconds(1); const int pipelineCapacity = _defaultPipelineCapacity; var pipeline = new AsyncPipeline(pipelineCapacity); int tasksCompleted = 0; // the following value is wrapped within an array to avoid a modified closure warning from ReSharper. int[] pipelineSize = { 0 }; var capacityReached = new InterlockedFlag(); Action workFunc = () => { var sz = Interlocked.Increment(ref pipelineSize[0]); CheckPipelineState(sz, pipelineCapacity, capacityReached); Task.Delay(delayLength).Wait(); Interlocked.Decrement(ref pipelineSize[0]); Interlocked.Increment(ref tasksCompleted); }; Action workerFunc = () => { for (var j = 0; j < loopCount; j++) { Task task = new Task(workFunc); pipeline.Add(task, whiteBox: null); task.Start(); } }; Func <Task> monitorFunc = async() => { var delay = TimeSpan.FromSeconds(5); while (tasksCompleted < expectedTasksCompleted) { Console.WriteLine("test in progress: tasksCompleted = {0}.", tasksCompleted); await Task.Delay(delay); } }; var workers = new Task[workerCount]; var stopwatch = Stopwatch.StartNew(); for (var i = 0; i < workerCount; ++i) { workers[i] = Task.Run(workerFunc); } Task.Run(monitorFunc).Ignore(); await Task.WhenAll(workers); pipeline.Wait(); stopwatch.Stop(); Assert.AreEqual(expectedTasksCompleted, tasksCompleted, "The test did not complete the expected number of tasks."); var targetTimeSec = expectedTasksCompleted * delayLength.TotalSeconds / pipelineCapacity; var minTimeSec = (1.0 - variance) * targetTimeSec; var maxTimeSec = (1.0 + variance) * targetTimeSec; var actualSec = stopwatch.Elapsed.TotalSeconds; Console.WriteLine( "Test finished in {0} sec, {1}% of target time {2} sec. Permitted variance is +/-{3}%", actualSec, actualSec / targetTimeSec * 100, targetTimeSec, variance * 100); Assert.IsTrue(capacityReached.IsSet, "Pipeline capacity not reached; the delay length probably is too short to be useful."); Assert.IsTrue( actualSec >= minTimeSec, string.Format("The unit test completed too early ({0} sec < {1} sec).", actualSec, minTimeSec)); Assert.IsTrue( actualSec <= maxTimeSec, string.Format("The unit test completed too late ({0} sec > {1} sec).", actualSec, maxTimeSec)); }