C#中的简单多线程程序无法工作
本文关键字:工作 程序 多线程 简单 | 更新日期: 2023-09-27 18:20:27
我正在尝试用C#编写一个简单的多线程程序。它按下一个按钮,在窗体上创建一个新标签,然后运行for循环,在标签中显示循环值。所以,如果您按下按钮3次,它将在带有循环的窗体上创建3个带有3个标签的线程。
我按一下按钮,效果很好。但当我多次按下它来创建更多标签时,它会遇到以下问题:
-
一旦按钮被按下多次,它就会停止上一个线程中的循环,并运行新线程的循环。如果它是多线程的,那么它不应该停止第一个循环。
-
当第二个标签的循环结束时,它给出以下错误
对象引用未设置为对象的实例
这是我的完整代码。引发错误的行在末尾"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++;
}
}
}
如果它是多线程的,那么它不应该停止第一个循环。
但它不是多线程的。
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复制到本地变量。在线程尚未终止的情况下,只要您按下两次按钮,它就会操作第二个线程。