C#中的简单多线程程序无法正常工作

时间:2012-01-17 12:48:53

标签: c# multithreading

我正在尝试用C#编写一个简单的多线程程序。它有一个按钮按下,在窗体上创建一个新标签,然后一个for循环运行显示标签中的循环值。因此,如果您按下按钮3次,它将在窗体上创建3个带有3个标签的线程。

当我按下按钮一次时,它工作正常。但是当我不止一次按下它来创建更多标签时,它会遇到以下问题:

  1. 只要多次按下按钮,它就会停止前一个线程中的循环并运行新线程的循环。如果它是多线程的,那么它不应该停止第一次循环。

  2. 当第二个标签的循环结束时,它会出现以下错误

  3.   

    对象引用未设置为对象的实例

    这是我的完整代码。抛出错误的行最后是“mylabel [tcount] .Text = i.ToString();”。

    程序截图:http://i.imgur.com/IFMIs.png

    代码http://i.imgur.com/sIXtc.png

    的屏幕截图
    namespace WindowsFormsApplication2{
        public partial class Form1 : Form{
            public Form1(){
                InitializeComponent();
            }
    
            private int tcount = 0;
            private int y_point = 0;
    
            Thread[] threads = new Thread[5];
            Label[] mylabel = new Label[5];
    
            private void button1_Click(object sender, EventArgs e){
                threads[tcount] = new Thread(new ThreadStart(work));
                threads[tcount].Start();
            }
    
            private void work(){
                if (this.InvokeRequired){
                    this.Invoke(new MethodInvoker(delegate{
                        mylabel[tcount] = new Label();
                        mylabel[tcount].Text = "label" + tcount;
                        mylabel[tcount].Location = new System.Drawing.Point(0, y_point + 15);
                        y_point += 25;
    
                        this.Controls.Add(mylabel[tcount]);
                        for (int i = 0; i < 10000; i++){
                            mylabel[tcount].Text = i.ToString();
                            Application.DoEvents();
                        }
                    }));
                }
                tcount++;
            }
            }
        }
    

3 个答案:

答案 0 :(得分:9)

  

如果它是多线程的,那么它不应该停止第一次循环。

但它不是多线程的。

  

this.Invoke(新的MethodInvoker(委托{

这会通过调用者将上下文切换回UI线程,所以当你在后台打开很多线程时,你基本上将所有处理放回到一个主线程中。

此:

  

Application.DoEvents();

然后给其他排队的工作一个机会。仍然只在UI线程上。

最后你永远不会对线程进行参数化,因此它们都可以处理相同的变量。只有一个非线程保存(无锁定,无易失性)变量名为tCount - bang。

基本上你证明:

  • 您的问题无法解决多线程问题 - 任何UI元素操作都会在UI线程上发生(这就是您调用的原因)而且这就是您所做的一切,您基本上无法进行多线程处理。
  • 您对UI程序如何使用线程和消息泵缺乏基本的了解。
  • 您对线程之间的变量scoing和访问模式缺乏基本的了解。

回到阅读文档我会说。

答案 1 :(得分:3)

问题是tcount的范围,因为所有线程都访问它的相同实例,所以一旦第二个线程启动,第一个线程也会进入第二个标签。

你也调用你的整个worker方法,让它再次在UI-Thread中运行 - &gt;实际上并不是多线程......

您的工人方法应如下所示:

private void work()
{
    int tIndex = tCount; //store the index of this thread
    tcount++;
    mylabel[tIndex] = new Label();
    mylabel[tIndex].Text = "label" + tcount;
    mylabel[tIndex].Location = new System.Drawing.Point(0, y_point + 15);
    y_point += 25;

    Invoke((MethodInvoker)delegate() { this.Controls.Add(mylabel[tIndex]); });

    for (int i = 0; i < 10000; i++)
    {
        //doWork
        Invoke((MethodInvoker)delegate() { mylabel[tIndex].Text = i.ToString(); });
    }
}

答案 2 :(得分:0)

Jep,您需要将tcount复制到本地变量。当一个线程尚未终止时,只要你按两次按钮,它就会操纵第二个按钮。