从线程调用可以工作,但不能更简单

本文关键字:但不能 更简单 工作 线程 调用 | 更新日期: 2023-09-27 18:03:02

我设法制作了一个简单的程序,从不同的线程和类更新一个TextBox。用可视化的方式学习穿线最简单的方法。;)

代码是用msdn的文档编写的。它运行,我没有看到内存泄漏。但是我有一种感觉,这可以做得更简单。

主要有两个类;表单和背景类。在后台类中有一个名为generateStream的函数,它通过委托给一个名为updateTextBox的函数来更新Form类中的TextBox。

当按下buttonStart时,执行两个操作。直接调用第一个generateStream。当generateStream准备好时,会创建一个线程再次运行generateStream(通过TheFunction)。当使用不同的线程时,TextBox需要调用解决方案。

所有这些都实现并工作。我认为这是相当多的代码,也许可以做得更干净。

主类中更新表单并被回调的函数。

public void updateTextBox(string strtext)
    {
        if (this.InvokeRequired) //When calling from another thread; invoke is required.
        {
            SetTextCallBack cb = new SetTextCallBack(updateTextBox);
            this.Invoke(cb, new object[] { strtext });
        }
        else //Call can be performed safely.
        {
            textBoxStatus.SelectionStart = textBoxStatus.Text.Length;
            textBoxStatus.AppendText(strtext);
            textBoxStatus.Update();
        }
    }

点击按钮完成的动作。

    private void buttonStart_Click(object sender, EventArgs e)
    {
        buttonStart.Enabled = false;
        /*
         * Step 1: Let's call the function blocking.
         *          The GUI will not respond to mouse geastures. Hoover mouse over inputbox to see no change in pointer.
         */
        bg.generateStream(numberOfCalls, "GUI Thread: ");

        /*
         * Step 2: Let's call the function in a seperate thread.
         *          The GUI will now respond to the mouse. Hoover mouse over inputbox to see pointer change.
         */
        Thread sepThread = new Thread(new ThreadStart(this.TheFunction));
        sepThread.Start();
        buttonStart.Enabled = true;
    }

后台类中的generateStream函数

    public void generateStream(int amountOfStreams, string inpString)
    {
        for (int i = 0; i < amountOfStreams; i++)
        {
            Thread.Sleep(1000); //Easy does it.
            myCallBack(inpString + i.ToString() + System.Environment.NewLine); //This is the text to the Main Form.
        }
    }

当使用线程时,我现在使用两个回调来更新文本框。一个从后台类到表单,另一个实现调用。是否有例如没有信号量解决方案,我的updateTextBox函数可以只有一个线程访问?

从线程调用可以工作,但不能更简单

当invokerrequired_true时调用Invoke是无害的。我也喜欢在c# 2.0中使用匿名方法。您可以将函数简化如下:

private delegate void SimpleProc();
private void updateTextBox(string strtext) {
    this.Invoke(new SimpleProc(delegate() {
        textBox1.SelectionStart = textBox1.Text.Length;
        textBox1.AppendText(strtext);
        textBox1.Update(); // only needed if updateTextBox is called from UI thread
    }), null);
}

用BeginInvoke代替Invoke对于"即发即弃"的场景很有用,在这种情况下,你不希望后台线程等待UI线程完成更新,但你需要确定这是否适合你的应用程序。

更新后的函数可以直接从UI线程或后台线程调用。不需要回调;唯一使用的回调是updateTextBox内部的匿名函数。没有比这更简单的了。实际上,在很多情况下,并不需要创建一个单独的函数来调用UI线程,这是非常简单的。

相关文章: