简单的线程处理 及同步:
public class MuThread { int a = 0; int i = 0; private volatile bool _run=true; public void method(object par) { while (_run) { Console.WriteLine("运行中"+par.ToString()); } Console.WriteLine("已结束"); } public void stop() { _run = false; } public void method1() { while (a < 100) { a++; Console.WriteLine("线程1输出:" + a); } } public void method2() { //当不加入线程同步代码的时候调用method1跟method2 会出现混乱 //但是通过数他们的输出行数依然是100行 //说明while判断是正确的 //当CPU分配时间片的时候 无论他们有多么接近 其实同一时间依然只有一个线程在访问变量a //但是线程1跟2是CPU随机分配时间片交替前进的 实现同一时间多个进度协同执行任务的效果 while (a < 100) { a++; Console.WriteLine("线程2输出:" + a); } } public void methodSyn1() { while (a < 100) { lock (this) { //意思是代码进入lock范围后 大括号内的代码将会被单独占用直到执行完 //而不会临时被其他时间片插入导致a的值已经更改 //当时间片继续回到此段时还沿用原来的 变量 导致混乱 //如果去掉前面的判断 会输出101 ,至于原理么跟孙鑫C++线程同步是一样的 也有Monitor.Entry() if (a < 100) { a++; Console.WriteLine("线程1输出:" + a); } } } } public void methodSyn2() { while (a < 100) { Monitor.Enter(this); if (a < 100) { a++; Console.WriteLine("线程2输出:" + a); } Monitor.Exit(this); } } }
线程示例:
static void Main() { //Service s = new Service(); //s.start(); //初始化MuThread的时候可以在构造函数 中传入一个方法引用也就是delegate //然后再MuThread实例的线程方法执行完毕后调用该delegate //这种编程方式我一直认为很高深 被那些砖家称之为"回调"callback //参见ms-help://MS.VSCC.v90/MS.MSDNQTR.v90.chs/dv_fxadvance/html/52b32222-e185-4f42-91a7-eaca65c0ab6d.htm MuThread m = new MuThread(); //ThreadStart 其实是一个委托 //在C++里就需要声明委托 //为了给方法传参数但是不能为每种类型都定义一个委托 所以只能传入object类型 //.Net为我们简化了的语法 Thread tPar = new Thread(m.method); tPar.Start("传入的参数"); //ParameterizedThreadStart委托显示语法 start()其实相当于Event.do() ParameterizedThreadStart del = new ParameterizedThreadStart(m.method); Thread tPar2 = new Thread(del); tPar2.Start("传入的参数"); Thread t = new Thread(new ThreadStart(m.method1)); Thread t2 = new Thread(new ThreadStart(m.method2)); t2.Start(); t.Start(); //利用volatile 参数的状态终止线程 while (!tPar.IsAlive) ; Thread.Sleep(100); m.stop(); //MSDN的意思是阻断当前调用t的线程 也就是Main 主线程 直到让t执行完毕 //事实确实是这样的 当不加Join()的时候 看着t.start()的语句在main方法下面的循环语句前面 //其实他们的时间片依然由CPU随机分配的 "主线程调用"这句输出是穿插在前面子线程输出一起的 //参见ms-help://MS.VSCC.v90/MS.MSDNQTR.v90.chs/fxref_mscorlib/html/56ed7b6f-efe0-67e7-34bc-766dd9f693f9.htm //当主线程 也就是Main方法里进行Thread.Sleep(200)时 其实是挂起主线程 这样就可以把时间片让给那些子线程 t.Join(); for (int i = 0; i < 50; i++) { Console.WriteLine("主线程调用"); } //使用线程池 //ms-help://MS.VSCC.v90/MS.MSDNQTR.v90.chs/dv_csref/html/5426dae4-c3f3-4e76-a998-19f7ca4baf3f.htm Console.ReadKey(); }
使用backgroundworker组件:
public partial class Form1 : Form { public Form1() { InitializeComponent(); backgroundWorker1.WorkerReportsProgress = true; backgroundWorker1.WorkerSupportsCancellation = true; button3.Enabled = false; } private void button2_Click(object sender, EventArgs e)//start { textBox1.Text = "开始产生10000以内的随机数。。。\n\n"; button2.Enabled = false; button3.Enabled = true; //在后台开始操作 backgroundWorker1.RunWorkerAsync(); } private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) { //不要直接使用组件实例名称(backgroundworker1)因为有多个backgroundworker时 //直接使用会产生耦合问题 应该通过下面的转换使用它 BackgroundWorker worker = sender as BackgroundWorker; //下面的内容相当于线程要处理的内容。//注意 不要在此事件中和界面控件打交道 Random r = new Random(); int numCount = 0; while (worker.CancellationPending==false) { int num = r.Next(10000); if (num%5==0) { numCount++; worker.ReportProgress(0, num); Thread.Sleep(1000); } } e.Result = numCount; } private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e) { int num = (int)e.UserState; textBox1.Text += num + " "; } private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) { if (e.Error==null) { textBox1.Text += "\n\n操作停止,共产生" + e.Result + "个能被5整除的随机数"; } else { textBox1.Text += "\n操作过程中产生错误:" + e.Error; } } private void button3_Click(object sender, EventArgs e) { backgroundWorker1.CancelAsync(); button3.Enabled = false; button2.Enabled = true; } }