C#任务UI死锁

时间:2018-08-01 14:58:09

标签: c# asynchronous task deadlock

我知道有很多关于Task死锁的帖子,但是我根本找不到合适的解决方案。

所以我基本上有以下设置:

public event EventHandler StateChangedEvent;
public bool Busy
{
    ...
    set
    {
        ...
        this.StateChangedEvent?.Invoke(this, EventArgs.Empty)
    }
}
public void Main()
{
    ...
    this.StateChangedEvent += this.OnStateChangedEvent;
}
public void OnStateChangedEvent(object sender, EventArgs e)
{
    this.TextBox.Invoke(() => this.TextBox.Text = "Change");
    this.Invoke(() => this.Cursor = Cursors.WaitCursor);
}
public void ButtonAction_Click(object sender, EventArgs e) //actually part of an API with an virtal - override method on between. Can't change here to async
{
    ...
    Task.Run(async () => await this.AsyncDoStuff()).Wait();
    ... // Synchron stuff needs to be done afterwards
}
public async Task AsyncDoStuff()
{
    this.Busy = true; //Causes Deadlock
    await Stuff1();
    await Stuff2();
}

因此,实际上,这些调用被划分在不同的类中,但是基本结构仍然保留。是的,我知道我应该一直保持异步状态,但是假设第一个ButtonAction_Click是API /框架的一部分,并且不能更改为异步状态。 我知道原因是因为我阻止了UI线程,然后再次访问它...那么对此的最佳解决方案是什么?

谢谢!

1 个答案:

答案 0 :(得分:0)

因此,从您的其他评论看来,ButtonAction_Click中的代码不在您的控制范围内,您无法更改。不幸的是,这就是问题所在-这个事件处理程序完全阻塞了UI线程,直到工作完成。无法取消阻塞线程。

您唯一的解决方法是避免与UI线程发生任何阻塞交互。

您的示例中的以下代码肯定会导致死锁,因为Invoke()会一直阻塞,直到UI(已被阻塞)响应为止:

this.TextBox.Invoke(() => this.TextBox.Text = "Change");
this.Invoke(() => this.Cursor = Cursors.WaitCursor);

您可以尝试使用BeginInvoke()而不是Invoke(),但是不幸的结果是,直到UI线程被解除阻止,然后您的后台工作已经完成,这些UI更改才会真正执行。不过,这可能会解决您的僵局。