Ejemplo n.º 1
0
        public void TestBoundedParallelInvokeForceSerialWithThreadLimiterAndParallelOptions()
        {
            var cnt        = 0;
            var parOptions = new ParallelOptions {
                MaxDegreeOfParallelism = 2
            };
            // ReSharper disable once RedundantArgumentDefaultValue
            var boundedParallel = new BoundedParallel(-1, 4);

            Parallel.Invoke(() =>
            {
                BoundedParallelInvoke(boundedParallel, 500, ref cnt, parOptions);
            }, () =>
            {
                BoundedParallelInvoke(boundedParallel, 500, ref cnt, parOptions);
            }, () =>
            {
                BoundedParallelInvoke(boundedParallel, 500, ref cnt, parOptions);
            }, () =>
            {
                BoundedParallelInvoke(boundedParallel, 500, ref cnt, parOptions);
            });
            Assert.AreEqual(12, cnt);
            Assert.IsTrue(boundedParallel.Stats.TotalParallelRunCount > 0, "TotalParallelRunCount should be higher than 0");
            Assert.IsTrue(boundedParallel.Stats.TotalSerialRunCount > 0, "TotalSerialRunCount should be higher than 0");
        }
Ejemplo n.º 2
0
        public void TestBoundedParallelInvokeForceSerialWithThreadLimiterForcingAllowance()
        {
            var cnt = 0;

            // ReSharper disable once RedundantArgumentDefaultValue
            using var waitEvent1 = new ManualResetEvent(false);
            using var waitEvent2 = new ManualResetEvent(false);
            var boundedParallel = new BoundedParallel(-1, 5);

            Parallel.Invoke(() =>
            {
                boundedParallel.Invoke(() =>
                {
                    waitEvent1.Set();
                    waitEvent2.WaitOne();
                    Thread.Sleep(1500);
                    Interlocked.Increment(ref cnt);
                },
                                       () =>
                {
                    Interlocked.Increment(ref cnt);
                }, () =>
                {
                    Interlocked.Increment(ref cnt);
                });
            }, () =>
            {
                boundedParallel.Invoke(() =>
                {
                    waitEvent1.WaitOne();
                    waitEvent2.Set();
                    Thread.Sleep(1500);
                    Interlocked.Increment(ref cnt);
                },
                                       () =>
                {
                    Interlocked.Increment(ref cnt);
                }, () =>
                {
                    Interlocked.Increment(ref cnt);
                });
            }, () =>
            {
                waitEvent1.WaitOne();
                waitEvent2.WaitOne();
                BoundedParallelInvoke(boundedParallel, 1000, ref cnt);
            }, () =>
            {
                waitEvent1.WaitOne();
                waitEvent2.WaitOne();
                BoundedParallelInvoke(boundedParallel, 1000, ref cnt);
            });
            Assert.AreEqual(12, cnt);
            Assert.AreEqual(2, boundedParallel.Stats.TotalSerialRunCount);
            Assert.AreEqual(2, boundedParallel.Stats.TotalParallelRunCount);
            Assert.AreEqual(5, boundedParallel.Stats.TotalParallelsThreadConsumed);
        }
Ejemplo n.º 3
0
        public virtual void Prepare()
        {
            if (_prepared)
            {
                throw new InvalidOperationException("DataReplicator already prepared.");
            }
            try
            {
                var sqlBuilder = (IClassSqlBuilder)typeof(TSourceAdapter);
                _sourceCmds = new List <DbCommand>();
                foreach (var sqlStatement in _sourceTables)
                {
                    _sourceCmds.Add(sqlStatement.Item4 ?? sqlBuilder.BuildCommand(sqlStatement.Item2, null));
                    sqlStatement.Item4 = null;
                }

                _sourceConnections  = new DbConnection[_sourceCmds.Count];
                _targetConnections  = new TTargetConn[_sourceCmds.Count];
                ColumnMetadataLists = new ColumnMetadataList[_sourceCmds.Count];
                _readers            = new List <DbDataReader> {
                    Capacity = _sourceCmds.Count
                };
                for (var i = 0; i < _sourceCmds.Count; i++)
                {
                    _readers.Add(null);
                }

                _parallelRunner = new BoundedParallel(1, ParallelismLevel);
                _parallelRunner.For(0, _sourceCmds.Count, i =>
                {
                    if (_sourceTables[i].Item4 != null)
                    {
                        _sourceConnections[i] = _sourceTables[i].Item4.Connection;
                    }
                    else
                    {
                        _sourceConnections[i] = sqlBuilder.BuildConnection(_sourceConnStr);
                    }
                    _sourceConnections[i].Open();

                    _sourceCmds[i].Connection = _sourceConnections[i];
                    var reader  = _sourceCmds[i].ExecuteReader();
                    _readers[i] = reader;

                    ColumnMetadataLists[i] = new ColumnMetadataListFromDbReader(reader);

                    _targetConnections[i] = GenericObjectBuilder.Build <TTargetConn>(_targetConnStr);
                    _targetConnections[i].Open();
                });
                _prepared = true;
            }
            catch (Exception)
            {
                UnPrepare(true);
                throw;
            }
        }
Ejemplo n.º 4
0
        public void TestBoundedParallelSimpleInvokeWithNoActions()
        {
            var boundedParallel = new BoundedParallel(3);
            var actions         = new Action[0];

            boundedParallel.Invoke(actions);
            Assert.AreEqual(1, boundedParallel.Stats.TotalSerialRunCount);
            Assert.AreEqual(0, boundedParallel.Stats.TotalParallelRunCount);
        }
Ejemplo n.º 5
0
        public void TestBoundedParallelSimpleForWithZeroItems()
        {
            var regularParallelResult = Parallel.For(0, 0, (n) => { });
            var boundedParallel       = new BoundedParallel(3);
            var boundedResult         = boundedParallel.For(0, 0, (n) => { });

            Assert.AreEqual(1, boundedParallel.Stats.TotalSerialRunCount);
            Assert.AreEqual(0, boundedParallel.Stats.TotalParallelRunCount);
            Assert.AreEqual(regularParallelResult.IsCompleted, boundedResult.IsCompleted);
        }
Ejemplo n.º 6
0
 public virtual void UnPrepare(bool skipPreparedCheck = false)
 {
     if (!_prepared && !skipPreparedCheck)
     {
         throw new InvalidOperationException("DataReplicator not prepared. Can't UnPrepare.");
     }
     Dispose();
     _parallelRunner     = null;
     ColumnMetadataLists = null;
     _prepared           = false;
 }
Ejemplo n.º 7
0
        public void TestBoundedParallelSimpleForEachCall()
        {
            var items           = new[] { 1, 2, 3 };
            var cnt             = 0;
            var boundedParallel = new BoundedParallel(3);
            var result          = boundedParallel.ForEach(items, (item) => { Interlocked.Increment(ref cnt); });

            Assert.AreEqual(3, cnt);
            Assert.IsTrue(boundedParallel.Stats.TotalSerialRunCount == 0, "TotalSerialRunCount must be zero");
            Assert.IsTrue(result.IsCompleted);
        }
Ejemplo n.º 8
0
        public void TestBoundedParallelSimpleInvokeCall()
        {
            var cnt             = 0;
            var boundedParallel = new BoundedParallel(3);

            BoundedParallelInvoke(boundedParallel, 0, ref cnt);
            Assert.AreEqual(3, cnt);
            Assert.IsTrue(boundedParallel.Stats.TotalSerialRunCount == 0, "TotalSerialRunCount must be zero");
            Assert.IsTrue(boundedParallel.Stats.TotalParallelRunCount != 0, "TotalParallelRunCount must not be zero");
            boundedParallel.ResetAllStats();
            Assert.AreEqual(0, boundedParallel.Stats.TotalParallelRunCount);
        }
Ejemplo n.º 9
0
        public void TestBoundedParallelSimpleForCall()
        {
            var items           = new[] { 1, 2, 3 };
            var sumItems        = 0;
            var boundedParallel = new BoundedParallel(3);

            boundedParallel.For(0, 3, (idx) =>
            {
                Interlocked.Add(ref sumItems, items[idx]);
            });
            Assert.AreEqual(6, sumItems);
            Assert.IsTrue(boundedParallel.Stats.TotalSerialRunCount == 0, "TotalSerialRunCount must be zero");
        }
Ejemplo n.º 10
0
        public void TestBoundedParallelArgumentsCheck()
        {
            var             boundedParallel     = new BoundedParallel();
            ParallelOptions nullParallelOptions = null;

            Assert.IsTrue(Assert.ThrowsException <ArgumentNullException>(() => boundedParallel.Invoke(nullParallelOptions, delegate { })).Message.Contains("parallelOptions"));
            Assert.IsTrue(Assert.ThrowsException <ArgumentNullException>(() => boundedParallel.Invoke(new ParallelOptions(), null)).Message.Contains("actions"));
            Assert.IsTrue(Assert.ThrowsException <ArgumentException>(() => boundedParallel.Invoke(new ParallelOptions(), new Action[] { null })).Message.Contains("null action"));
            Assert.IsTrue(Assert.ThrowsException <ArgumentNullException>(() => boundedParallel.For(0, 1, nullParallelOptions, delegate { })).Message.Contains("parallelOptions"));
            Assert.IsTrue(Assert.ThrowsException <ArgumentNullException>(() => boundedParallel.For(0, 1, new ParallelOptions(), null)).Message.Contains("body"));
            IEnumerable <int> nullEnumerable = null;

            Assert.IsTrue(Assert.ThrowsException <ArgumentNullException>(() => boundedParallel.ForEach(nullEnumerable, new ParallelOptions(), delegate { })).Message.Contains("source"));
            Assert.IsTrue(Assert.ThrowsException <ArgumentNullException>(() => boundedParallel.ForEach(new List <int>(), null, delegate { })).Message.Contains("parallelOptions"));
            Assert.IsTrue(Assert.ThrowsException <ArgumentNullException>(() => boundedParallel.ForEach(new List <int>(), new ParallelOptions(), null)).Message.Contains("body"));
        }
Ejemplo n.º 11
0
        public void TestPrivateTryParallelDelegate()
        {
            // ReSharper disable once RedundantArgumentDefaultValue
            var boundedParallel = new BoundedParallel(2)
            {
                AbortOnSerialInvocationException = false
            };
            var methodInfo = boundedParallel.GetType().GetMethod("TryParallel",
                                                                 BindingFlags.NonPublic | BindingFlags.Instance, null,
                                                                 new[] { typeof(BoundedParallel.ParallelInvokeDelegate), typeof(int) }, null);

            Assert.IsNotNull(methodInfo);
            var tryParallel = (TryParallelDelegate)Delegate.CreateDelegate(typeof(TryParallelDelegate), boundedParallel, methodInfo);

            Assert.AreEqual(0, boundedParallel.ConcurrentInvocationsCount);
            Assert.AreEqual(0, boundedParallel.ConcurrentThreadsCount);
            var delegateCalled = false;
            var retVal         = tryParallel(count =>
            {
                Assert.AreEqual(1, boundedParallel.ConcurrentInvocationsCount);
                Assert.AreEqual(2, boundedParallel.ConcurrentThreadsCount);
                Parallel.For(0, 1, idx => delegateCalled = true);
            }, 2);

            Assert.IsTrue(retVal);
            Assert.IsTrue(delegateCalled);
            Assert.AreEqual(0, boundedParallel.ConcurrentInvocationsCount);
            Assert.AreEqual(0, boundedParallel.ConcurrentThreadsCount);

            boundedParallel.MaxParallelInvocations = 1;
            var innerDelegateCalled = false;
            var retValOuter         = tryParallel(countOuter =>
            {
                delegateCalled = true;
                retVal         = tryParallel(count =>
                {
                    innerDelegateCalled = true;
                }, 2);
            }, 2);

            Assert.IsTrue(retValOuter);
            Assert.IsFalse(retVal);
            Assert.IsTrue(delegateCalled);
            Assert.IsFalse(innerDelegateCalled);
            Assert.AreEqual(0, boundedParallel.ConcurrentInvocationsCount);
            Assert.AreEqual(0, boundedParallel.ConcurrentThreadsCount);
        }
Ejemplo n.º 12
0
        public void TestBoundedParallelForEachForceSerial()
        {
            var items = new[] { 1, 2, 3 };
            var cnt   = 0;
            // ReSharper disable once RedundantArgumentDefaultValue
            var boundedParallel = new BoundedParallel(2);

            Parallel.Invoke(() =>
            {
                boundedParallel.ForEach(items, (item) =>
                {
                    Thread.Sleep(1500);
                    Interlocked.Increment(ref cnt);
                });
            }, () =>
            {
                boundedParallel.ForEach(items, (item) =>
                {
                    Thread.Sleep(1500);
                    Interlocked.Increment(ref cnt);
                });
            }, () =>
            {
                Thread.Sleep(500);
                var result1 = boundedParallel.ForEach(items, (item) =>
                {
                    Thread.Sleep(500);
                    Interlocked.Increment(ref cnt);
                });
                Assert.IsTrue(result1.IsCompleted);
            }, () =>
            {
                Thread.Sleep(500);
                var result2 = boundedParallel.ForEach(items, (item) =>
                {
                    Thread.Sleep(500);
                    Interlocked.Increment(ref cnt);
                });
                Assert.IsTrue(result2.IsCompleted);
            });

            Assert.AreEqual(12, cnt);
            Assert.IsTrue(boundedParallel.Stats.TotalSerialRunCount > 0, "TotalSerialRunCount should be > 0");
        }
Ejemplo n.º 13
0
        public void TestBoundedParallelInvokeWithThreadLimitDiffIncrements()
        {
            var cnt             = 0;
            var boundedParallel = new BoundedParallel();

            boundedParallel.Invoke(() =>
            {
                Interlocked.Add(ref cnt, 1);
            }, () =>
            {
                Interlocked.Add(ref cnt, 2);
            }, () =>
            {
                Interlocked.Add(ref cnt, 3);
            }, () =>
            {
                Interlocked.Add(ref cnt, 4);
            });
            Assert.AreEqual(10, cnt);
        }
Ejemplo n.º 14
0
        // ReSharper disable once IdentifierTypo
        private static void BoundedParallelInvoke(BoundedParallel boundedParallel, int withSleep, ref int pcnt, ParallelOptions parOptions = null)
        {
            parOptions ??= new ParallelOptions();
            var cnt = 0;

            boundedParallel.Invoke(parOptions, () =>
            {
                if (withSleep > 0)
                {
                    Thread.Sleep(withSleep);
                }
                Interlocked.Increment(ref cnt);
            }, () =>
            {
                Interlocked.Increment(ref cnt);
            }, () =>
            {
                Interlocked.Increment(ref cnt);
            });
            Interlocked.Add(ref pcnt, cnt);
        }
Ejemplo n.º 15
0
        public void TestBoundedParallelForForceSerial()
        {
            var items    = new[] { 1, 2, 3 };
            var sumItems = 0;
            // ReSharper disable once RedundantArgumentDefaultValue
            var boundedParallel = new BoundedParallel(2);

            Parallel.Invoke(() =>
            {
                boundedParallel.For(0, 3, (idx) =>
                {
                    Thread.Sleep(500);
                    Interlocked.Add(ref sumItems, items[idx]);
                });
            }, () =>
            {
                boundedParallel.For(0, 3, (idx) =>
                {
                    Thread.Sleep(500);
                    Interlocked.Add(ref sumItems, items[idx]);
                });
            }, () =>
            {
                boundedParallel.For(0, 3, (idx) =>
                {
                    Thread.Sleep(500);
                    Interlocked.Add(ref sumItems, items[idx]);
                });
            }, () =>
            {
                boundedParallel.For(0, 3, (idx) =>
                {
                    Thread.Sleep(500);
                    Interlocked.Add(ref sumItems, items[idx]);
                });
            });

            Assert.AreEqual(24, sumItems);
            Assert.IsTrue(boundedParallel.Stats.TotalSerialRunCount > 0, "TotalSerialRunCount should be > 0");
        }
Ejemplo n.º 16
0
        public void TestBoundedParallelInvokeForceSerialWithThreadLimiter()
        {
            var cnt = 0;
            // ReSharper disable once RedundantArgumentDefaultValue
            var boundedParallel = new BoundedParallel(-1, 2);

            Parallel.Invoke(() =>
            {
                BoundedParallelInvoke(boundedParallel, 500, ref cnt);
            }, () =>
            {
                BoundedParallelInvoke(boundedParallel, 500, ref cnt);
            }, () =>
            {
                BoundedParallelInvoke(boundedParallel, 500, ref cnt);
            }, () =>
            {
                BoundedParallelInvoke(boundedParallel, 500, ref cnt);
            });
            Assert.AreEqual(12, cnt);
            Assert.IsTrue(boundedParallel.Stats.TotalSerialRunCount > 0, "TotalSerialRunCount should be > 0");
        }
Ejemplo n.º 17
0
        public void TestBoundedParallelInvokeForceSerialAndThenSomeParallel()
        {
            var cnt = 0;
            // ReSharper disable once RedundantArgumentDefaultValue
            var boundedParallel = new BoundedParallel(2);

            Parallel.Invoke(() =>
            {
                BoundedParallelInvoke(boundedParallel, 1000, ref cnt); // Parallel
            }, () =>
            {
                BoundedParallelInvoke(boundedParallel, 1000, ref cnt); // Parallel
            }, () =>
            {
                Thread.Sleep(500);
                BoundedParallelInvoke(boundedParallel, 2000, ref cnt); // One action serial and two in Parallel
            });
            Assert.AreEqual(9, cnt);
            Assert.AreEqual(1, boundedParallel.Stats.TotalSerialRunCount);
            Assert.AreEqual(3, boundedParallel.Stats.TotalParallelRunCount);
            Assert.AreEqual(8, boundedParallel.Stats.TotalParallelsThreadConsumed);
        }
Ejemplo n.º 18
0
        public void TestBoundedParallelSimpleInvokeCallThrowsException()
        {
            var cnt             = 0;
            var boundedParallel = new BoundedParallel(3);
            var e = Assert.ThrowsException <AggregateException>(() =>
                                                                boundedParallel.Invoke(() =>
            {
                Interlocked.Increment(ref cnt);
                throw new Exception("Explosion");
            }, () =>
            {
                Interlocked.Increment(ref cnt);
                throw new Exception("Explosion");
            }, () =>
            {
                Interlocked.Increment(ref cnt);
            }));

            Assert.AreEqual(3, cnt);
            Assert.IsTrue(boundedParallel.Stats.TotalSerialRunCount == 0, "TotalSerialRunCount must be zero");
            Assert.AreEqual(2, e.InnerExceptions.Count);
        }
Ejemplo n.º 19
0
        public void TestPrivateGetAllowedThreadCount()
        {
            // ReSharper disable once RedundantArgumentDefaultValue
            var boundedParallel = new BoundedParallel(2)
            {
                AbortOnSerialInvocationException = false
            };
            var methodInfo = boundedParallel.GetType()
                             .GetMethod("GetAllowedThreadCount", BindingFlags.NonPublic | BindingFlags.Instance);

            Assert.IsNotNull(methodInfo);
            var getAllowedThreadCount =
                (GetAllowedThreadCountDelegate)Delegate.CreateDelegate(typeof(GetAllowedThreadCountDelegate),
                                                                       boundedParallel, methodInfo);

            boundedParallel.MaxParallelThreads = 3;
            Assert.AreEqual(2, getAllowedThreadCount(4, 2)); // Could fit one thread of the two requested, which makes no sense so returns requestedThreadCount
            Assert.AreEqual(2, getAllowedThreadCount(3, 2)); // Exact fit of the two requests
            Assert.AreEqual(2,
                            getAllowedThreadCount(5, 2));    // Could not fit even 1 thread, returned requestedThreadCount
            boundedParallel.MaxParallelThreads = BoundedParallel.Unlimited;
            Assert.AreEqual(2, getAllowedThreadCount(8, 2)); // Could fit both thread. Using unlimited ThreadLimit
        }
Ejemplo n.º 20
0
        public void TestBoundedParallelStressTest1BoundedSucceedsContainingThreads()
        {
            Assert.IsTrue(ThreadPool.SetMinThreads(25, 10));
            var cnt             = 0;
            var boundedParallel = new BoundedParallel(4, 5);
            var actions         = new Action[20000];

            for (var i = 0; i < actions.Length; i++)
            {
                actions[i] = () =>
                {
                    Interlocked.Increment(ref cnt);
                    for (var j = 0; j < 5000; j++)
                    {
                        Thread.Sleep(0);
                    }
                }
            }
            ;
            boundedParallel.Invoke(actions);
            Assert.AreEqual(actions.Length, cnt);
            Assert.IsTrue(boundedParallel.Stats.TotalSerialRunCount == 0, "TotalSerialRunCount must == 0");
            Assert.IsTrue(Process.GetCurrentProcess().Threads.Count < 50, "WorkerThreads should be < 50");
        }
Ejemplo n.º 21
0
        public void Pump(IList <ISourceAdapter <TRow> > sourceAdapters, RowsJoinedDelegate onRowsJoined)
        {
            try
            {
                _finishThread       = false;
                _itemAvailableEvent = new ManualResetEventSlim(false);
                var targetAdapters = new List <PassThruTargetAdapter <TRow> >();
                foreach (var dummy in sourceAdapters)
                {
                    targetAdapters.Add(new PassThruTargetAdapter <TRow>(ProcessRow)
                    {
                        AbortOnProcessException = true
                    });
                }

                _rowsQueues         = new ConcurrentQueue <TRow> [targetAdapters.Count];
                _rowsProcessedCount = new int[targetAdapters.Count];
                _finished           = new bool[targetAdapters.Count];

                for (var i = 0; i < _rowsQueues.Length; i++)
                {
                    _rowsQueues[i] = new ConcurrentQueue <TRow>();
                }

                var processingThread = new Thread(ProcessRows);
                processingThread.Start(onRowsJoined);

                var boundedParallel = new BoundedParallel(1, targetAdapters.Count);
                boundedParallel.For(0, sourceAdapters.Count, index =>
                {
                    var pipeline             = new DataPipeline <TRow>();
                    targetAdapters[index].Id = index;
                    pipeline.AfterTargetAdapterProcessRow += (a, row) =>
                    {
                        _rowsProcessedCount[index]++;
                        for (var idx = 0; idx < _finished.Length; idx++)
                        {
                            if (_finished[idx] && _rowsProcessedCount[index] > _rowsProcessedCount[idx])
                            {
                                throw new DataPipelineAbortedException();
                            }
                        }
                    };
                    pipeline.Pump(sourceAdapters[index], targetAdapters[index]);
                    _finished[index] = true;
                });

                _finishThread = true;
                _itemAvailableEvent.Set();
                processingThread.Join();

                if (_threadException != null)
                {
                    throw _threadException;
                }
                CheckOutOfBalanceSourceAdapters();
                foreach (var queue in _rowsQueues)
                {
                    if (!queue.IsEmpty)
                    {
                        throw new DataPipelineAbortedException();
                    }
                }
            }
            finally
            {
                _threadException    = null;
                _rowsQueues         = null;
                _itemAvailableEvent = null;
            }
        }
Ejemplo n.º 22
0
 public UnitTestConcurrentStackedBagSlim()
 {
     _parallel = new BoundedParallel(2, 4);
     _parallel.For(0, 1000, i => { }); // warm-up
 }
Ejemplo n.º 23
0
        public void TestCreateBoundedParallel()
        {
            var boundedParallel = new BoundedParallel();

            Assert.IsNotNull(boundedParallel);
        }
Ejemplo n.º 24
0
        public void TestBoundedParallelInvokeForceSerialThrowsException()
        {
            var cnt = 0;
            // ReSharper disable once RedundantArgumentDefaultValue
            var boundedParallel = new BoundedParallel(2)
            {
                AbortOnSerialInvocationException = false
            };

            Assert.ThrowsException <AggregateException>(() =>
                                                        Parallel.Invoke(() =>
            {
                BoundedParallelInvoke(boundedParallel, 500, ref cnt);
            }, () =>
            {
                BoundedParallelInvoke(boundedParallel, 500, ref cnt);
            }, () =>
            {
                boundedParallel.Invoke(() =>
                {
                    Thread.Sleep(500);
                    Interlocked.Increment(ref cnt);
                    throw new Exception();
                },
                                       () =>
                {
                    Interlocked.Increment(ref cnt);
                }, () =>
                {
                    Interlocked.Increment(ref cnt);
                });
            }, () =>
            {
                boundedParallel.Invoke(() =>
                {
                    Thread.Sleep(500);
                    Interlocked.Increment(ref cnt);
                },
                                       () =>
                {
                    Interlocked.Increment(ref cnt);
                }, () =>
                {
                    Interlocked.Increment(ref cnt);
                });
            }));
            Assert.AreEqual(12, cnt);
            Assert.IsTrue(boundedParallel.Stats.TotalSerialRunCount > 0, "TotalSerialRunCount should be > 0");

            using var startedThread1Event = new ManualResetEvent(false);
            using var startedThread2Event = new ManualResetEvent(false);
            boundedParallel.AbortOnSerialInvocationException = true;
            cnt = 0;
            Assert.ThrowsException <AggregateException>(() =>
                                                        Parallel.Invoke(() =>
            {
                boundedParallel.Invoke(() =>
                {
                    startedThread1Event.Set();
                    Thread.Sleep(500);
                    Interlocked.Increment(ref cnt);
                },
                                       () =>
                {
                    Interlocked.Increment(ref cnt);
                }, () =>
                {
                    Interlocked.Increment(ref cnt);
                });
            }, () =>
            {
                boundedParallel.Invoke(() =>
                {
                    startedThread2Event.Set();
                    Thread.Sleep(500);
                    Interlocked.Increment(ref cnt);
                },
                                       () =>
                {
                    Interlocked.Increment(ref cnt);
                }, () =>
                {
                    Interlocked.Increment(ref cnt);
                });
            }, () =>
            {
                startedThread1Event.WaitOne();
                startedThread2Event.WaitOne();
                boundedParallel.Invoke(() =>
                {
                    Interlocked.Increment(ref cnt);
                    throw new Exception();
                },
                                       () =>
                {
                    Interlocked.Increment(ref cnt);
                }, () =>
                {
                    Interlocked.Increment(ref cnt);
                });
            }, () =>
            {
                startedThread1Event.WaitOne();
                startedThread2Event.WaitOne();
                boundedParallel.Invoke(() =>
                {
                    Thread.Sleep(500);
                    Interlocked.Increment(ref cnt);
                },
                                       () =>
                {
                    Interlocked.Increment(ref cnt);
                }, () =>
                {
                    Interlocked.Increment(ref cnt);
                });
            }));
            Assert.AreEqual(10, cnt);
            Assert.IsTrue(boundedParallel.Stats.TotalSerialRunCount > 0, "TotalSerialRunCount should be > 0");
        }