// a specific repro where inner queries would see an ODE on the merged cancellation token source // when the implementation involved disposing and recreating the token on each worker thread private static bool Cancellation_ODEIssue() { bool passed = true; AggregateException caughtException = null; try { Enumerable.Range(0, 1999).ToArray() .AsParallel().AsUnordered() .WithExecutionMode(ParallelExecutionMode.ForceParallelism) .Zip <int, int, int>( Enumerable.Range(1000, 20).Select <int, int>(_item => (int)_item).AsParallel().AsUnordered(), (first, second) => { throw new OperationCanceledException(); }) .ForAll(x => { }); } catch (AggregateException ae) { caughtException = ae; } //the failure was an ODE coming out due to an ephemeral disposed merged cancellation token source. passed &= TestHarnessAssert.IsTrue(caughtException != null, "We expect an aggregate exception with OCEs in it."); return(passed); }
// After running a plinq query, we expect the internal cancellation token source to have been disposed. // The critical thing is that there are no callbacks left hanging on the external tokens callback list, else we // could be causing an accumulation of junk that will not GC until the external token goes away (possibly never). private static bool Bugfix626345_PlinqShouldDisposeLinkedToken() { bool passed = true; TestHarness.TestLog("* PlinqCancellationTests.Bugfix626345_PlinqShouldDisposeLinkedToken()"); #if DEBUG // Only run these in debug mode, because they rely on a debug-only property. PropertyInfo callbackCountProperty = typeof(CancellationTokenSource). GetProperty("CallbackCount", BindingFlags.Instance | BindingFlags.NonPublic); if (callbackCountProperty == null) { TestHarness.TestLog(" - Error: CancellationTokenSource.CallbackCount property not found; was it removed?"); return(false); } Func <CancellationTokenSource, int> getCallbackCount = _ => (int)callbackCountProperty.GetValue(_, null); CancellationTokenSource cts = new CancellationTokenSource(); CancellationToken ct = cts.Token; // ForAll Enumerable.Range(1, 10).AsParallel().WithCancellation(ct).ForAll((x) => { }); passed &= TestHarnessAssert.IsTrue(getCallbackCount(cts) == 0, "The callback list should be empty."); // Built-in-aggregation Enumerable.Range(1, 10).AsParallel().WithCancellation(ct).Average(); passed &= TestHarnessAssert.IsTrue(getCallbackCount(cts) == 0, "The callback list should be empty."); // Manual aggregation Enumerable.Range(1, 10).AsParallel().WithCancellation(ct).Aggregate((a, b) => a + b); passed &= TestHarnessAssert.IsTrue(getCallbackCount(cts) == 0, "The callback list should be empty."); // ToArray (uses ToList, which enumerates the query with foreach()) Enumerable.Range(1, 10).AsParallel().WithCancellation(ct).ToArray(); passed &= TestHarnessAssert.IsTrue(getCallbackCount(cts) == 0, "The callback list should be empty."); // AsynchronousChannelMergeEnumerator foreach (int x in Enumerable.Range(1, 10).AsParallel().WithCancellation(ct).Select(xx => xx)) { } passed &= TestHarnessAssert.IsTrue(getCallbackCount(cts) == 0, "The callback list should be empty."); // SynchronousChannelMergeEnumerator foreach (int x in Enumerable.Range(1, 10).AsParallel().WithCancellation(ct).WithMergeOptions(ParallelMergeOptions.FullyBuffered)) { } passed &= TestHarnessAssert.IsTrue(getCallbackCount(cts) == 0, "The callback list should be empty."); // Fallback to sequential foreach (int x in Enumerable.Range(1, 10).AsParallel().WithCancellation(ct).Where(xx => true).Skip(4)) { } passed &= TestHarnessAssert.IsTrue(getCallbackCount(cts) == 0, "The callback list should be empty."); #endif return(passed); }
// Tests that the shared state variable seems to be working correctly. private static bool RunManualResetEventSlimTest4_CombinedStateTests() { bool passed = true; TestHarness.TestLog("* RunManualResetEventSlimTest4_CombinedStateTests()"); ManualResetEventSlim mres = new ManualResetEventSlim(false, 100); int expectedCount = Environment.ProcessorCount == 1 ? 1 : 100; passed &= TestHarnessAssert.AreEqual(expectedCount, mres.SpinCount, "Spin count did not write/read correctly, expected " + expectedCount + ", actual " + mres.SpinCount); passed &= TestHarnessAssert.IsFalse(mres.IsSet, "Set did not read correctly."); mres.Set(); passed &= TestHarnessAssert.IsTrue(mres.IsSet, "Set did not write/read correctly."); return(passed); }