C# 调用导致任务永远不会完成

本文关键字:永远 任务 调用 | 更新日期: 2023-09-27 18:31:25

这是我的代码:

public void ReadCodes(){
        Task compute = Task.Run(() =>
        {
             //foo code
             foreach (var line in lines)
             {
                 //some other codes
                 SetText("doing something");
             }
        });
        compute.Wait();
        //some other foo
}
private void SetText(string text)
{
        if (this.lblUsedFiles.InvokeRequired)
        {
                SetTextCallback d = new SetTextCallback(SetText);
                this.Invoke(d, new object[] { text });
        }
        else
        {
                this.lblUsedFiles.Text = text;
        }
}

当我删除SetText("doing something")调用时ReadCodes()函数有效,否则它会挂起。我的代码有什么问题?我想更新 Task.Run() 中的 UI。

C# 调用导致任务永远不会完成

您的ReadCodes方法(可能在 UI 线程上执行)生成一个新任务,并阻止等待它 - UI 线程在完成之前不能执行任何其他操作。

但是,您的任务(在线程池上运行)调用 Invoke 以在 UI 线程上运行操作,在此操作完成之前也会阻塞。由于两个操作都在等待对方时被阻塞,因此两者都无法继续,从而导致死锁。

要解决此问题,最简单的解决方案通常是将Invoke替换为 BeginInvoke ,允许您的任务继续(并完成),而无需等待 UI 更新。任务完成后,将释放 UI 线程,并处理挂起的 UI 更新。

编辑:为了回答更新以包含循环的问题:我建议您使用异步模式(在 C# 5 中引入)。这将完全消除 UI 线程阻塞,并允许您在处理每一行后立即执行 UI 更新。

public async Task ReadCodes()
{
    foreach (var line in lines)
    {
        string text = await Task.Run(() =>
        {
            //foo code
            // return text;
        });
        this.lblUsedFiles.Text = text;
    }
    //some other foo
}

编辑2:我已经根据Peter Duniho的评论更新了我的代码。由于 ReadCodes 大概是在 UI 线程上调用的,因此您可以在等待每个任务时直接在其中更新 UI(无需Invoke)。我假设在//some other codes中执行的后台处理可以集成到后续迭代的//foo code中。