【问题标题】:Threading: Application Freezes after using Thread.Join()线程:使用 Thread.Join() 后应用程序冻结
【发布时间】:2015-05-16 13:52:16
【问题描述】:

我知道 .Join() 会导致线程暂停并等待线程完成其工作,但是如何避免 UI 被冻结?这就是我的代码的样子”

Thread dataThread = new Thread(()=> data = getData(id));
dataThread.Start();
dataThread.Join();

Thread storingThread = new Thread(()=> storeData(data));
storingThread.Start();

我需要加入,因为第一个线程返回一个包含需要通过第二个线程存储的数据的对象。但这会导致 UI 冻结。我怎样才能在后台线程中实现这些?你们觉得我应该改变什么?

【问题讨论】:

  • 您使用的是哪个版本的框架? >= 4.5?
  • 是的,伙计@FlorianMoser
  • 您可能想探索 async / await 关键字的功能。我会在几秒钟内发布答案
  • @FlorianMoser 抱歉,我正在运行 4.0。但是是的,请告诉我:)
  • 为什么创建一个线程只为了立即Join呢?如果您不熟悉线程并正在创建 WinForms 应用程序,请考虑使用BackgroundWorker

标签: c# .net multithreading .net-4.0


【解决方案1】:

如果您使用 .Net framework >= 4.5,您可以使用 Tasks

await Task.Run(() => data = getData(id));
await Task.Run(() => storeData(data));

或者在一个命令中

await Task.Run(() => storeData(getData(id)));

如果您不必等到完成,您也可以这样做:

Task.Run(() => storeData(getData(id)));

【讨论】:

  • 这给出了一个错误:'await' 运算符只能在异步方法中使用。考虑使用“async”修饰符标记此方法并将其返回类型更改为“Task”。
  • @Earthling 将async modifire 添加到您的函数中。例如您的正常功能是 private void DoStuff() 然后将其更改为 private async void DoStuff()
  • @Simon 如果他使用的是 .Net 4,则其 Task.Factory.StartNew 无需等待。
  • 不用担心我修好了 :)
【解决方案2】:

看来你不需要两个线程:

Thread dataThread = new Thread(() => storeData(getData(id)));
dataThread.Start();

请注意,Task 优于 Thread。另外,您可能应该使用 await。

【讨论】:

  • 这应该是我认为的公认答案。特别是当它在 .NET 4 下编译时。另外,它可以说是单线程更优雅
  • @MickyDuncan 这也有效,但我使用 Task 而不是 Threads,它似乎可以解决问题! :)
  • 在启动新线程时有效。它可能会产生比需要更多的开销。任务不一定在新线程上开始(节省开销)。见stackoverflow.com/a/13429164/1277156(更多解释)
  • 当然,我认为这不是一个好的解决方案。这是让他的代码工作所需的最小增量。他让事情变得比需要的更复杂。
  • 它满足了.NET4的OP要求,无需大刀阔斧的重写。
【解决方案3】:

将整个工作放到一个线程中,这样 UI 就不会停止:

 ThreadPool.QueueUserWorkItem( () => storeData(getData(id)));

或者对于 .Net 4

Task.Factory.StartNew(() => storeData(getData(id)));

【讨论】:

  • 在你使用这个之前你可以这样做ThreadPool.QueueUserWorkItem( () => storeData(getData(id)));
  • @Simon...我同意,让我改变答案。
  • @MickyDuncan 我不同意你所说的,我的目标只是将操作从用户的 GUI 线程中移开,以改变挂起的外观系统。我猜他以后可以优化这个过程。
  • 已经 使用ThreadPool.QueueUserWorkItem“关闭了GUI线程”
  • @MickyDuncan 我已经更新了答案的第一部分以匹配第二部分;以避免任何混淆。
【解决方案4】:

使用 async / await 关键字。小示例代码:

private async void Method()
{
     var result = await ExecuteAsync();
     // result == true 
}

private async Task<bool> ExecuteAsync()
{
     //run long running action
     return true;
}

在 .net 4.0 中,您需要安装 Microsoft.Bcl.Async 才能使用此功能。

可以在http://blog.stephencleary.com/2012/02/async-and-await.html阅读此功能的一个很好的介绍

【讨论】:

【解决方案5】:

答案已经给出。作为一个额外的,我给我的。

你也可以像这样使用 ContinueWith:

Task<string>.Factory.StartNew(() => "Hey!").ContinueWith(t => Console.WriteLine(t.Result));

【讨论】:

  • 这有点矫枉过正。用户甚至还不知道 TPL
  • @Simon 我只是把它扔掉了。这是普通的C#。过度杀伤是有争议的。虽然我同意它更先进。
  • 这与 OP 问题中提供的 getData()storeData 上下文有什么关系?
  • @MickyDuncan 他可以将 Task 替换为 Task.Factory.StartNew() => getData(id)).ContinueWith(t => storeData(t.Result)) 和也适用于 .net 4。
  • 是的,但考虑重写它,以便 OP 不需要进行任何重写。谢谢
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-05-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多