如何在Task.Wait中出现死锁 [英] how there can be Deadlock in Task.Wait

查看:109
本文介绍了如何在Task.Wait中出现死锁的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述



在CLR中通过C#book提到


"当一个线程调用Wait方法时, 系统检查线程正在等待的任务是否已开始执行。如果有,则调用Wait的线程将阻塞,直到Task完成运行。但是如果Task还没有启动
执行,那么系统可以(取决于TaskScheduler)通过使用名为Wait"的线程执行任务。


"如果线程在调用Wait之前已经进行了线程同步锁定,然后Task尝试采用相同的锁定,从而导致死锁线程!"



我无法理解第二部分,如何发生死锁。它的任务是在同一个线程上执行,然后任务应该能够获取锁,因为同一个线程已经锁定。有人可以用简单的示例解释死锁是如何发生的吗



谢谢

解决方案

首先,要明确的是,他们试图说的是由任务调度程序决定如何执行任务(大多数情况下)。 .NET附带了几个任务调度程序,任何人都可以创建自己的任务调度程序。由于执行任务是调度程序
的责任,因此您不应该对如何安排任务做出任何假设。 


当您调用Task.Wait时,它会查找看看任务是否完成(随时上网并查看Task的源代码)。如果是,则返回,否则旋转等待,直到超时到期或任务完成。旋转等待涉及
,产生线程以允许(其他)线程运行的时间。因为它产生这意味着当前线程没有运行,因此该线程上的代码不会执行。


它正在谈论的死锁场景很容易发生在您使用同步上下文(即UI或不使用ConfigureAwait)的情况下。在这种情况下,很容易使UI线程死锁(并且不仅仅是因为这个原因)。在
订单中,UI线程可以继续处理消息。为了实现这一点,它必须正在监听消息。如果你阻止了线程,那么就无法监听消息,因此会死锁。

 public partial class Form1:Form 
{
public Form1()
{
InitializeComponent();
}

private void button1_Click(object sender,EventArgs e)
{
var task = DoWorkAsync();

task.Wait();
}

私有异步任务DoWorkAsync()
{
//在UI线程上运行

//将从方法返回并运行辅助线程上的余数
await Task.Delay(1000);

//未使用ConfigureAwait返回UI线程,但UI线程被阻止
//等待任务完成 - 死锁

等待任务。延迟(2000年);
}
}


但在其他情况下也会发生这种情况。





Hi,

in CLR via C# book it is mentioned that

"When a thread calls the Wait method, the  system checks if the Task that the thread is waiting for has started executing. If it has, then the thread calling Wait will block until the Task has completed running. But if the Task has not started executing yet, then the system may (depending on the TaskScheduler) execute the Task by using the thread that called Wait".

"if the thread has taken a thread synchronization lock before calling Wait and then the Task tries to take the same lock, resulting in a deadlocked thread!"

I am not able to understand the second part, how deadlock can happen. it the task is executing on the same thread, then task should be able to acquire lock, as the same thread has taken lock. Can somebody pls explain with simple sample how deadlock can happen

Thanks

解决方案

Firstly, to be clear, what they are trying to say is that it is up to the task scheduler how to execute tasks (for the most part). .NET ships with a couple of task schedulers and anyone can create their own. Since executing tasks is the responsibility of the scheduler you shouldn't make any assumption about how the task will be scheduled. 

When you call Task.Wait it looks to see if the task is completed (feel free to go online and look at the source code for Task). If it is then it returns otherwise it spin waits until either the timeout expires or the task completes. Spin waiting involves yielding the thread to allow time for the (other) thread to run. Since it yields that means the current thread isn't running and hence no code on that thread will execute.

The deadlock scenario it is talking about can easily occur in situations where you are using a sync context (i.e. a UI or not using ConfigureAwait). In this case it is easy to deadlock the UI thread (and for more than just this reason). In order for the UI thread to work it continually pumps messages. For that to happen it has to be listening for messages. If you block the thread then it cannot listen for messages and therefore will deadlock.

public partial class Form1 : Form
{
    public Form1 ()
    {
        InitializeComponent();
    }

    private void button1_Click ( object sender, EventArgs e )
    {
        var task = DoWorkAsync();

        task.Wait();
    }

    private async Task DoWorkAsync ()
    {
        //Running on UI thread 

        //Will return from method and run remainder on secondary thread
        await Task.Delay(1000);

        //Didn't use ConfigureAwait so back on UI thread but UI thread is blocked
        //wait for the task to complete - deadlock

        await Task.Delay(2000);
    }
}

It can happen in other cases as well though.


这篇关于如何在Task.Wait中出现死锁的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆