从一个线程调用工作但不能做得更简单?

时间:2011-07-19 19:38:22

标签: c# multithreading forms

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

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

有两个主要类别; Form和BackGround类。在BackGround类中有一个名为generateStream的函数,它通过委托给一个名为updateTextBox的函数更新Form类中的TextBox。

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

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

更新表单的mainclass中的函数,并被回调。

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;
    }

BackGround类中的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.
        }
    }

使用线程时,我现在使用两个回调来更新TextBox。一个从BackGround类到Form,另一个用于实现Invoke。例如,没有信号量解决方案可能我的updateTextBox函数只能有一个线程访问?

1 个答案:

答案 0 :(得分:3)

当InvokeRequired为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线程。