【问题标题】:Event after Thread isAlive线程 isAlive 之后的事件
【发布时间】:2011-12-30 08:22:40
【问题描述】:

我有一个带有“正在加载”文本标签的表单。

label1.Text = "Loading...";

在 Form.Load 中,我有一个正在做某事的新线程,可以这么说。

void Form_Load(object sender, EventArgs args)
{
   Thread t = new Thread(run);
   t.Start();
}  

void run()
{
   for(int i = 0; i < 1000000; i++)
   {

   }
}

我想在线程“t”完成后将label1.Text 属性更改为“已完成”。但是在哪里以及如何改变我不知道。我正在学习线程。我是否必须再创建一个线程来持续检查线程“t”的isAlive 属性?

【问题讨论】:

  • Task切换到BackgroundWorker不是更简单吗?

标签: c# winforms multithreading c#-4.0


【解决方案1】:

如果您愿意使用Async CTP 提出的asyncawait 关键字,那么这是一个非常酷的解决方案。

public async void Form_Load(object sender, EventArgs args)
{
  label1.Text = "Loading..."
  // Do some more stuff here if necessary.
  label1.Text = await Run();
}

private Task<string> Run()
{
  var tcs = new TaskCompletionSource<string>();
  Task.Factory.StartNew(
    () =>
    {
      for (int i = 0; i < 1000000; i++)
      {
      }
      tcs.SetResult("Finished");
    });
    return tcs.Task;
}

【讨论】:

    【解决方案2】:

    如果您的任务确实在另一个线程中做某事并将结果发布到 gui 中,您应该查看BackgroundWorker 类。

    如果您无法做到这一点,您可以查看threading article of Joe。它应该真正回答您关于线程的所有问题。

    如果您需要后台工作人员的进一步帮助,只需在网络上或在 SO 上进行搜索。 Here is one of my answers,展示了如何使用后台工作者。

    【讨论】:

      【解决方案3】:

      看看 .NET4 附带的TPL Task Parallel Library。这使您有机会轻松启动后台工作人员并定义在第一个任务完成后要启动的另一个任务。真正聪明的是,第二个任务(与其他任务一样)可以配置为在 UI 线程上运行,这样您就不必在任务操作中进行切换。

      喜欢这里的小样本:

      var task = new Task(() =>
      {
          // DoSomething very long in background
      }).ContinueWith(previousTask =>
          {
              // Do some action on UI thread
          },
          TaskScheduler.FromCurrentSynchronizationContext());
      
      task.Start();
      

      【讨论】:

      • 如果样本基于我的问题,我将不胜感激,以便我更好地理解。网络或文章上的任何相关示例也是可观的。谢谢。我从来没有听说过。
      • @rapsalands: 已添加 :-)
      • 我在前一个做过....这对我的问题是准确的,但你的对长期知识很有好处。谢谢。
      【解决方案4】:

      您有多种解决方案。如果你真的想使用 Thread 类,你可以调用 Join 方法,但这会阻塞 UI 线程,这不是一件好事。您也可以在“for”循环之后立即调用表单的 Invoke 方法

      void run()
      {
          for (int i = 0; i < 100000000; i++)
          {
          }
      
          this.Invoke(new Action(() => this.label1.Text = "done"));
      }
      

      invoke 方法是必需的,因为您是在 windows 窗体中,invoke 方法将在 UI 线程上执行您的代码。

      除了使用 Thread 类,您还可以查看 Delegate.BeginInvoke 和 System.Threading.Tasks。它们都更有效,因为它汇集了线程和提供回调来分离您的拆卸代码。

      【讨论】:

      • 这对于现实生活来说是一个糟糕的解决方案,因为表单和线程最终会紧密耦合。
      【解决方案5】:

      简单

      void run()
      {
         for(int i = 0; i < 1000000; i++)
         {
      
         }
      
         Invoke(new MethodInvoker(delegate()
                                               {
                                                   label1.Text = "finished";
      
                                               }));
      }
      

      或者你提出了一个事件,但在这种简单的情况下,这样做并不重要

      【讨论】:

      • 什么不起作用?我有相同的代码,它可以工作...... :-)
      【解决方案6】:

      将标签或表单的引用传递给您的线程并使用Invokelabel1.Text="Completed"

      【讨论】:

        【解决方案7】:

        不,一点也不。您需要向 UI 线程(处理表单的线程)发送一条消息。阅读本文以获取一些信息:How to update the GUI from another thread in C#?

        【讨论】:

          【解决方案8】:

          可能最简单的做法是让run 在事件完成时引发事件,并让表单将处理程序附加到该事件。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2012-01-17
            • 1970-01-01
            • 2013-12-10
            • 2011-09-19
            • 1970-01-01
            相关资源
            最近更新 更多