我知道有很多关于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线程,然后再次访问它...那么对此的最佳解决方案是什么?
谢谢!
答案 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更改才会真正执行。不过,这可能会解决您的僵局。