【问题标题】:Method not gets called from task delegate未从任务委托调用方法
【发布时间】:2018-04-17 09:23:01
【问题描述】:

我正在尝试使用System.Threading.Tasks.Task 类实现并行处理。奇怪的是,任务委托的执行在第一次方法调用时就停止了。我在下面的示例代码中编码以重新创建问题。

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);
        }
    }
}

我调用方法TestClass.Bar() 来调用TestClass 的静态构造函数。 主线程按预期在Task.WaitAll(tasks) 调用处等待并行任务。但它永远不会完成,因为任务本身卡在 Foo 方法调用中。

其中一项卡住任务的堆栈跟踪:

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()

有人能指出为什么 Foo 方法没有被调用吗?

【问题讨论】:

标签: c# .net parallel-processing task .net-4.6.2


【解决方案1】:

静态构造函数只能执行一次。当您在类上调用任何方法时 - 必须执行静态构造函数(如果尚未执行),除非它目前已经在执行。在这种情况下,第二次调用应该等到静态构造函数完成。

您在静态构造函数中启动多个任务,然后使用Task.WaitAll 阻止它们以完成。

但是,每个任务也会调用同一个类的静态方法(Foo)。每个这样的调用都必须等待静态构造函数完成(因为它目前正在执行)。但它永远不会发生,因为静态构造函数被阻塞等待任务完成,而任务被阻塞等待静态构造函数完成,所以你有一个经典的死锁。

【讨论】:

  • 很好发现,认为它与静态构造函数有关,但我无法完全理解它。
  • 我有一种感觉,这是一个僵局,并且由于静态性质的原因。但从未接近真正的原因。很好看!
猜你喜欢
  • 1970-01-01
  • 2011-08-12
  • 2020-01-26
  • 2013-07-02
  • 1970-01-01
  • 2015-06-09
相关资源
最近更新 更多