diff --git a/src/Numerics/Threading/Parallel.cs b/src/Numerics/Threading/Parallel.cs index dbab88c8..83315988 100644 --- a/src/Numerics/Threading/Parallel.cs +++ b/src/Numerics/Threading/Parallel.cs @@ -67,7 +67,9 @@ namespace MathNet.Numerics.Threading // fast forward execution in case parallelization is disabled // (cdrnet, 200908): should we fast forward on STA threads as well? - if (Control.DisableParallelization || ThreadQueue.ThreadCount <= 1) + if (Control.DisableParallelization + || ThreadQueue.ThreadCount <= 1 + || ThreadQueue.IsInWorkerThread) { for (int i = fromInclusive; i < toExclusive; i++) { @@ -136,7 +138,9 @@ namespace MathNet.Numerics.Threading // fast forward execution in case parallelization is disabled // (cdrnet, 200908): should we fast forward on STA threads as well? - if (Control.DisableParallelization || ThreadQueue.ThreadCount <= 1) + if (Control.DisableParallelization + || ThreadQueue.ThreadCount <= 1 + || ThreadQueue.IsInWorkerThread) { for (int i = 0; i < actions.Length; i++) { diff --git a/src/Numerics/Threading/ThreadQueue.cs b/src/Numerics/Threading/ThreadQueue.cs index cfcdd780..555b41c9 100644 --- a/src/Numerics/Threading/ThreadQueue.cs +++ b/src/Numerics/Threading/ThreadQueue.cs @@ -77,6 +77,12 @@ namespace MathNet.Numerics.Threading /// internal static int ThreadCount { get; private set; } + /// + /// Indicating whether the current thread is a parallelized worker thread. + /// + [ThreadStatic] + private static bool _isInWorkerThread; + /// /// Initializes static members of the ThreadQueue class. /// @@ -85,6 +91,14 @@ namespace MathNet.Numerics.Threading Start(Environment.ProcessorCount); } + /// + /// Gets a value indicating whether the current thread is a parallelized worker thread. + /// + internal static bool IsInWorkerThread + { + get { return _isInWorkerThread; } + } + /// /// Add a job to the queue. /// @@ -131,6 +145,8 @@ namespace MathNet.Numerics.Threading /// private static void WorkerThreadStart() { + _isInWorkerThread = true; + while (_running) { // Wait until a job is available, or we should shut down diff --git a/src/UnitTests/ThreadingTests/ParallelTest.cs b/src/UnitTests/ThreadingTests/ParallelTest.cs index 2e114dff..cc05e732 100644 --- a/src/UnitTests/ThreadingTests/ParallelTest.cs +++ b/src/UnitTests/ThreadingTests/ParallelTest.cs @@ -143,5 +143,48 @@ namespace MathNet.Numerics.UnitTests.ThreadingTests Assert.AreEqual(1001, items[i], i.ToString()); } } + + [Test, ApartmentState(ApartmentState.MTA)] + public void DoesDetectAndResolveRecursiveParallelization() + { + int countSharedBetweenClosures = 0; + + Assert.DoesNotThrow( + () => + Parallel.For( + 0, + 10, + j => Interlocked.Increment(ref countSharedBetweenClosures))); + + Assert.AreEqual(10, countSharedBetweenClosures); + countSharedBetweenClosures = 0; + + Parallel.For( + 0, + 10, + i => + Parallel.For( + 0, + 10, + j => Interlocked.Increment(ref countSharedBetweenClosures))); + + Assert.AreEqual(100, countSharedBetweenClosures); + countSharedBetweenClosures = 0; + + Parallel.For( + 0, + 10, + i => + Parallel.For( + 0, + 10, + j => + Parallel.For( + 0, + 10, + k => Interlocked.Increment(ref countSharedBetweenClosures)))); + + Assert.AreEqual(1000, countSharedBetweenClosures); + } } } \ No newline at end of file