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

本文关键字:工作 程序 多线程 简单 | 更新日期: 2023-09-27 18:20:27

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

我按一下按钮,效果很好。但当我多次按下它来创建更多标签时,它会遇到以下问题:

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

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

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

这是我的完整代码。引发错误的行在末尾"mylabel[tcount].Text=i.ToString();".

节目截图:https://i.stack.imgur.com/4MHOP.png

代码截图https://i.stack.imgur.com/S0tQ0.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++;
        }
        }
    }

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

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

但它不是多线程的。

this.Invoke(new MethodInvoker(delegate{

这通过调用程序将上下文切换回UI线程,因此当您在后台打开许多线程时,基本上可以将所有处理放回一个主线程中。

此:

Application.DoEvents();

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

最后,你永远不会参数化线程,所以它们都在同一个变量上工作。只有一个名为tCount-bang的非线程保存(无锁,无易失性)变量。

基本上你展示了:

  • 您的问题无法通过多线程解决——任何UI元素操作都必须在UI线程上进行(这就是您调用的原因),因为这就是您所要做的全部,所以基本上不能使用多线程
  • 您对UI程序如何使用线程和消息泵缺乏基本的了解
  • 您对线程之间的变量搜索和访问模式缺乏基本了解

回到阅读文档,我想说。

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

此外,您还调用了整个worker方法,这将使它再次在UI线程中运行->实际上不是多线程的。。。

你的工作者方法应该是这样的:

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

Jep,您需要将tcount复制到本地变量。在线程尚未终止的情况下,只要您按下两次按钮,它就会操作第二个线程。