【问题标题】:How to call a function after thread finished?线程完成后如何调用函数?
【发布时间】:2018-12-28 12:36:35
【问题描述】:

我尝试在线程完成后调用一个函数,但我不能。 我只能在我的函数调用代码之前使用while(threadName.isAlive) 方法,但它不好因为当我使用此代码时程序停止。你有什么想法吗?

public partial class Form1 : Form
{
    Thread myThread;
    string myString = string.Empty;

    public Form1()
    {
        InitializeComponent();
    }

    private void button1_Click(object sender, EventArgs e)
    {
        myThread = new Thread(write);
        myThread.Start();
        while (myThread.IsAlive) ;
        textBox1.Text = myString; 
    }

    public void write()
    {
        for (int i = 0; i < 10; i++) {

            myString += "aaa " + i + "\r\n";
            Thread.Sleep(1000);
        }
    }
}

【问题讨论】:

  • 请添加您的代码
  • 看来你想要的是Task,而不是ThreadmyTask.ContinueWith(...)
  • Thread 非常关注机制。你可以创建一个Task,正如其他人所说的那样,这更现代,或者你可以让自己完全更新并接受async/await。这样做,您甚至可以在适当的时候直接与 UI 交互(如果 Thread.Sleep 变为 Task.Delay 并表示 I/O 工作而不是 CPU 工作)
  • 首先要学习的是,你应该(几乎)永远不要使用线程。使用任务和异步/等待。

标签: c# multithreading


【解决方案1】:

如果您必须附加到Thread 而不是Task,那么您可以启动一个任务以等待线程退出,然后运行一些额外的代码,如下所示:

using System;
using System.Threading;
using System.Threading.Tasks;

namespace Demo
{
    static class Program
    {
        static void Main()
        {
            Thread thread = new Thread(work);
            thread.Start();

            Task.Run(() =>
            {
                thread.Join();
                Console.WriteLine("Run after thread finished");
            });

            Console.ReadLine();
        }

        static void work()
        {
            Console.WriteLine("Starting work");
            Thread.Sleep(1000);
            Console.WriteLine("Finished work");
        }
    }
}

但是,解决此问题的现代方法是使用 Taskawaitasync

例如:

async void button1_Click(object sender, EventArgs e)
{
    textBox1.Text = "Awaiting task";
    await writeAsync();
    textBox1.Text = "Task finished";
}

Task writeAsync()
{
    return Task.Run(() => write());
}

void write()
{
    Thread.Sleep(10000);
}

如果您尝试第二种方法,您会看到 UI 在文本框显示“等待任务”时保持响应。

另请注意,通常您希望阻止用户在等待任务时再次按下按钮,以避免运行多个任务。最简单的方法是在任务处于活动状态时禁用按钮,如下所示:

async void button1_Click(object sender, EventArgs e)
{
    button1.Enabled = false;

    textBox1.Text = "Awaiting task";
    await writeAsync();
    textBox1.Text = "Task finished";

    button1.Enabled = true;
}

【讨论】:

  • 我只是想学习。我使用此代码,我想使用 textbox 而不是 console.writeline 。但它给了我这个错误-> System.Windows.Forms.dll 中发生了“System.InvalidOperationException”类型的异常,但未在用户代码中处理附加信息:跨线程操作无效:控件“textBox1”从线程不是创建它的线程。
  • @amirmehr 如果您看到我的第二个示例,它将向您展示如何执行此操作。但是,请注意,您需要 .Net 4.5 或更高版本(我认为)才能这样做。
【解决方案2】:

Thread 切换到 Task 并让 .Net 为您完成(低级)工作:

public async Task<string> write() {
  string myString = string.Empty;

  for (int i = 0; i < 10; i++) {
    myString += "aaa " + i + "\r\n";

    await Task.Delay(1000);
  }

  return myString;
}

private async void button1_Click(object sender, EventArgs e) {
  string result = await write();    

  // continue with (please, notice await) with assigning
  textBox1.Text = result; 
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-01-10
    • 2021-03-19
    • 2019-02-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-02-09
    • 1970-01-01
    相关资源
    最近更新 更多