1

I'm trying to achieve parallel processing using System.Threading.Tasks.Task class. Strangely, task delegate execution is halted at the first method call. I coded below sample code to recreate the issue.

using System;
using System.Threading.Tasks;

namespace TestApp
{
    public static class TestClass
    {
        static TestClass()
        {
            var tasks = new Task[Environment.ProcessorCount];
            for (int i = 0; i < Environment.ProcessorCount; i++)
            {
                var task = Task.Run(() =>
                {
                    Console.WriteLine("Start the Task " + i);

                    // Method Foo is not called. 
                    // Stack trace show a managed to native transition.
                    // Why? 
                    Foo(i);
                });
                tasks[i] = task;
            }

            Task.WaitAll(tasks);
            Console.WriteLine("Press eny key to exit");
            Console.ReadKey();
        }

        private static void Foo(int i)
        {
            Console.WriteLine("Foo in the Task " + i);
        }
    }
}

I call the Method TestClass.Bar() to invoke the static constructor of TestClass. Main thread waits for the parallel tasks at the Task.WaitAll(tasks) call as expected. But it never complete because the tasks itself are stuck at the Foo method call.

Stack trace of one of the stuck tasks:

TestApp.exe!TestApp.TestClass..cctor.AnonymousMethod__0
[Managed to Native Transition]
TestApp.exe!TestApp.TestClass..cctor.AnonymousMethod__0() Line 18
mscorlib.dll!System.Threading.Tasks.Task.InnerInvoke()
mscorlib.dll!System.Threading.Tasks.Task.Execute()
mscorlib.dll!System.Threading.Tasks.Task.ExecutionContextCallback(object obj)
mscorlib.dll!System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state, bool preserveSyncCtx)
mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state, bool preserveSyncCtx)
mscorlib.dll!System.Threading.Tasks.Task.ExecuteWithThreadLocal(ref System.Threading.Tasks.Task currentTaskSlot)
mscorlib.dll!System.Threading.Tasks.Task.ExecuteEntry(bool bPreventDoubleExecution)
mscorlib.dll!System.Threading.Tasks.Task.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem()
mscorlib.dll!System.Threading.ThreadPoolWorkQueue.Dispatch()
mscorlib.dll!System.Threading._ThreadPoolWaitCallback.PerformWaitCallback()

Can someone suggest why the method Foo does not get called?

Kavinda Gayashan
  • 387
  • 4
  • 17

1 Answers1

6

Static constructor must be executed only one time. When you call any method on your class - static constructor must be executed (if not already), unless it's already executing at the moment. In such case, second call should wait until static constructor is completed.

You start several tasks in static constructor and then block with Task.WaitAll for them to complete.

However, each task also calls static method (Foo) of the same class. Each such call must wait for static constructor to complete (because it's executing at the moment). But it will never happen, because static constructor is blocked by waiting on tasks to complete, and tasks are blocked waiting for static constructor to complete, so you have a classic deadlock.

Evk
  • 98,527
  • 8
  • 141
  • 191
  • 1
    well spotted, thought it has something to do with the static constructor, but couldn't get my head completely around it. – René Vogt Apr 17 '18 at 09:30
  • I had a feeling that it is a deadlock and something because of the static nature. But never came close to the actual cause. Well spotted! – Kavinda Gayashan Apr 17 '18 at 10:48