我试了下为什么是正确的? using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Windows.Forms; using System.Threading;namespace WindowsApplication188 { public partial class Form1 : Form { ListBox LB = new ListBox();
public Form1() { InitializeComponent(); LB.Parent =this; Button B = new Button(); B.Location = new Point(0, 200); B.Parent = this; B.Click += new EventHandler(Submit_Click); } Thread[] trd = new Thread[20];//线程数组 public int trd_cnt = -1;//公共变量 private void Submit_Click(object sender, EventArgs e) { trd_cnt++; if (trd_cnt > trd.Length - 1) return; trd[trd_cnt] = new Thread(new ThreadStart(delegate { ThreadTask(trd_cnt, String.Empty, String.Empty, DateTime.Now); })); trd[trd_cnt].Start(); } private void ThreadTask(int list_no, string StrSN, string SeleProd, DateTime event_time) { this.Invoke(new Action<String>(DoSetString), new Object[] { list_no .ToString ()}); } void DoSetString(String S) { LB.Items.Add(S); } } } 0 1 2 3 4 5 6 7 8 9 10
Thread[] trd = new Thread[20];//线程数组
public int trd_cnt=-1//公共变量private void Submit_Click(object sender, EventArgs e)
{
trd_cnt++;
thr[trd_cnt]= new Thread(new ThreadStart(delegate { ThreadTask(trd_cnt, StrSN, SeleProd, event_time); }));
}private void ThreadTask(int list_no, string StrSN, string SeleProd,DateTime event_time)
{//do something}
修改后
先赋值
list_no=trd_cnt
然后传入list_nothr[list_no]= new Thread(new ThreadStart(delegate { ThreadTask(list_no, StrSN, SeleProd, event_time); }));
2. 建议将线程执行函数单独定义。
3. 多线程访问同一个全局变量要加锁。
4. 既然是一个全局变量,你没必要将这个变量通过参数传递。
5. 建议你将读取和修改trd_cnt数值做成两个方法,其中修改trd_cnt的方法要对trd_cnt进行加锁。
加锁的代码
Thread[] trd = new Thread[20];//线程数组
public int trd_cnt=-1//公共变量 private void Submit_Click(object sender, EventArgs e)
{
lock(object)
{
trd_cnt++;
}
thr[trd_cnt]= new Thread(new ThreadStart(delegate { ThreadTask( StrSN, SeleProd, event_time); }));
} private void ThreadTask( string StrSN, string SeleProd,DateTime event_time)
{lock(object)
{int list_no=trd_cnt;
}
//do something}
LZ,你在线程函数体外加锁,多个线程同时运行时仍然会取到过时的数值,你在线程函数体内加锁,就是把你那段修改trd_cnt的Lock代码加到ThreadTask函数体内。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Threading;namespace WindowsApplication188
{
public partial class Form1 : Form
{
ListBox LB = new ListBox();
public Form1()
{
InitializeComponent(); LB.Parent =this; Button B = new Button();
B.Location = new Point(0, 200);
B.Parent = this;
B.Click += new EventHandler(Submit_Click);
} Thread[] trd = new Thread[20];//线程数组
public int trd_cnt = -1;//公共变量 private void Submit_Click(object sender, EventArgs e)
{
trd_cnt++;
if (trd_cnt > trd.Length - 1)
return;
trd[trd_cnt] = new Thread(new ThreadStart(delegate { ThreadTask(trd_cnt, String.Empty, String.Empty, DateTime.Now); }));
trd[trd_cnt].Start();
} private void ThreadTask(int list_no, string StrSN, string SeleProd, DateTime event_time)
{
this.Invoke(new Action<String>(DoSetString), new Object[] { list_no .ToString ()});
} void DoSetString(String S)
{
LB.Items.Add(S);
}
}
}
0
1
2
3
4
5
6
7
8
9
10
19
LZ,你把代码修改为:private void Submit_Click(object sender, EventArgs e)
{
lock(object)
{
trd_cnt++;
//int list_no=trd_cnt;
thr[trd_cnt]= new Thread(new ThreadStart(delegate { ThreadTask(
StrSN, SeleProd, event_time); }));
}
}private void ThreadTask( string StrSN, string SeleProd,DateTime event_time)
{
//do something
}另,你与其用数组来存储线程对象,不如用List或Hashtable来替换,线程New出来后,把线程加入到List或Hashtable里面去,然后再启动,这样你就能避免维护trd_cnt这个全局变量。如果你确实要维护这个变量也可以,提个思路:
List<Thread> threadPool = new List<Thread>();
DealingFunction()
{
Thread tempTrd = new Thread(new ThreadStart(delegate { ThreadTask(
StrSN, SeleProd, event_time); }));
trd_cnt++; //这个变量在这里确实多次一举
threadPool.Add(tempTrd);
tempTrd.start();
}
{
for(long i = 0; i < 10000000000000; i++);
LB.Items.Add(S);
}
然后快速单击 submit按钮 试试看。
{
lock (o)
{
trd_cnt++;
if (trd_cnt > trd.Length - 1)
return;
trd[trd_cnt] = new Thread(new ThreadStart(delegate { ThreadTask(trd_cnt, String.Empty, String.Empty, DateTime.Now); }));
trd[trd_cnt].Start();
}
}
也就是他的本意 函数应该实参是:
ThreadTask(1,String.Empty, String.Empty)
ThreadTask(2,String.Empty, String.Empty)
ThreadTask(3,String.Empty, String.Empty)
但为什么它的第一个参数会根据trd_cnt变动 改成了:
ThreadTask(3,String.Empty, String.Empty)
ThreadTask(3,String.Empty, String.Empty)
ThreadTask(3,String.Empty, String.Empty)
我想楼主表到了这样一个意思吧, 至于它的线程执行代码有没有耗时 和这个问题我觉得一点关系都没有, 个人感觉就是闭包问题,就像我在13,14楼说到的那样
另外 在线程里面并没有对全局变量进行修改 只是读取。天芮:threadstart 不能接受非匿名委托啊 如果可以的话 你提供一下代码
EnoughPoint:即使将thread实例lock 还是不能解决这个问题
运行提示在不同步的代码里调用同步方法
private void Submit_Click(object sender, EventArgs e)
{
Monitor.Enter(trd_cnt); trd_cnt++;
if (trd_cnt > trd.Length - 1)
return;
trd[trd_cnt] = new Thread(new ThreadStart(delegate { ThreadTask(trd_cnt, String.Empty, String.Empty, DateTime.Now); }));
trd[trd_cnt].Start(); Monitor.Exit(trd_cnt);
}
控件 有没有简单的用委托的 然后赋值到子线程里面?
thr[trd_cnt]= new Thread(new ThreadStart(delegate { ThreadTask(trd_cnt, StrSN, SeleProd, event_time); })); //改动成以下
class WorkThreadParam
{
public string Parm1;
public string Parm2;
public int Parm3;
} thr[trd_cnt]= new Thread(new ParameterizedThreadStart(ThreadTask));
WorkThreadParam newParm = new WorkThreadParam();
newParm.Parm3 = trd_cnt;
newParm.Parm1 = string.Empty;
newParm.Parm2 = string.Empty; thr[trd_cnt].Start(newParm); void ThreadTask(object a)
{
//在这里会从thr[trd_cnt].Start(newParm)那里接受newParm 它是一个WorkThreadParam类型参数,强行转换过来然后用就可以了
}
代码没经过测试 不过基本就这么用,这样可以消除闭包效应 不过有点麻烦,还不如就你上面那种方法 把它赋值给一个临时变量,这个临时变量由于生存期关系它会和你的委托绑定,不会造成那种闭包效应
thr[trd_cnt]= new Thread(new ThreadStart(delegate { ThreadTask(trd_cnt, StrSN, SeleProd, event_time); })); 上 这个写法应该是vs2008才能写的,2008也特别提出了闭包的概念,虽然在以前的VS版本上也有闭包用法 但是2008还是第一个比较系统的提出了闭包
以前像在vs2005 中 int i=1;string a= (i+2+3).ToString() 其实就是一个闭包写法