是什么导致僵局? [重复]

问题描述 投票:5回答:2

这个问题在这里已有答案:

我在一段代码中遇到了僵局问题。值得庆幸的是,我已经能够在下面的例子中重现这个问题。作为普通的.Net Core 2.0控制台应用程序运行。

class Class2
{

    static void Main(string[] args)
    {
        Task.Run(MainAsync);
        Console.WriteLine("Press any key...");
        Console.ReadKey();
    }

    static async Task MainAsync()
    {
        await StartAsync();
        //await Task.Delay(1);  //a little delay makes it working
        Stop();
    }


    static async Task StartAsync()
    {
        var tcs = new TaskCompletionSource<object>();
        StartCore(tcs);
        await tcs.Task;
    }


    static void StartCore(TaskCompletionSource<object> tcs)
    {
        _cts = new CancellationTokenSource();
        _thread = new Thread(Worker);
        _thread.Start(tcs);
    }


    static Thread _thread;
    static CancellationTokenSource _cts;


    static void Worker(object state)
    {
        Console.WriteLine("entering worker");
        Thread.Sleep(100);  //some work

        var tcs = (TaskCompletionSource<object>)state;
        tcs.SetResult(null);

        Console.WriteLine("entering loop");
        while (_cts.IsCancellationRequested == false)
        {
            Thread.Sleep(100);  //some work
        }
        Console.WriteLine("exiting worker");
    }


    static void Stop()
    {
        Console.WriteLine("entering stop");
        _cts.Cancel();
        _thread.Join();
        Console.WriteLine("exiting stop");
    }

}

我期望的完整序列如下:

Press any key...
entering worker
entering loop
entering stop
exiting worker
exiting stop

但是,实际序列在Thread.Join调用上停止:

Press any key...
entering worker
entering stop

最后,如果我在MainAsync身体插入一个小延迟,一切都很顺利。为什么(哪里)发生死锁?

注意:在原始代码中,我使用SemaphoreSlim而不是TaskCompletionSource解决,并且根本没有问题。我只想了解问题所在。

c# multithreading task deadlock taskcompletionsource
2个回答
3
投票

在基础任务完成之前,tcs.SetResult(null);Worker()中的调用将不会返回(有关详细信息,请查看this question)。在你的情况下,任务状态是WaitingForActivation这就是你遇到死锁的原因:

  1. 执行Worker()的线程被tcs.SetResult(null)调用阻止。
  2. 执行Stop()的线程被_thread.Join()调用阻止。

0
投票

因为MainAsync()线程比其他线程'更快'。并且你只对不在线程上的任务进行控制!

在你的方法MainAsync()你等待方法StartAsync()完成它的工作,然后你启动线程。一旦方法StartAsync()完成其工作(创建并启动线程),该函数通知MainAsync()完成其工作。然后MainAsync()调用Stop方法。但你的线程在哪里?它并行运行,没有任何控制,并试图完成其工作。这不是死锁,任务和线程之间没有同步。

这就是为什么当你把await Task.Delay(1)你的代码工作,因为线程足够快,在任务结束之前完成工作(thread.join)。

© www.soinside.com 2019 - 2024. All rights reserved.