简单的线程处理 及同步:
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(); }
又反复测试了下join其实感觉就像endInvoke 就是阻止,说白了把指定的线程join到当前主线程 说白了就是阻塞操作 可不就是endInvoke么 ,到trd.Join()的 地方位置 必须要等待trd执行完毕
使用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; } }
一些关于匿名委托 和lambda表达式的写法 ,还有异步调用:
1 public void callDel(Func<int,int,int> dd) 2 { 3 int rst = dd.Invoke(5, 2); 4 Console.WriteLine("call Func rst is:{0}", rst); 5 } 6 7 public int method1() 8 { 9 10 //delDone.WaitOne(2000); 11 Thread.Sleep(2000); 12 13 return 1; 14 } 15 16 public delegate int MyDele(); 17 ManualResetEvent delDone = new ManualResetEvent(false); 18 private void Form3_Load(object sender, EventArgs e) 19 { 20 21 //waitone的作用 仅仅是阻断当前行代码以后的部分继续执行 22 //然后在回调里证明已经回调已经完成了 继续放行 23 //实际上是一种失去异步意义的一种方式 ,线程同步 24 delDone.Reset(); 25 MyDele d4 = new MyDele(method1); 26 d4.BeginInvoke((iar) => 27 { 28 int rdmResult = d4.EndInvoke(iar); 29 Console.WriteLine("iar call back state :" + iar.AsyncState.ToString()); 30 Console.WriteLine("iar call back rst is :{0}", rdmResult); 31 delDone.Set(); 32 }, "ss"); 33 //delDone.Set(); 34 delDone.WaitOne(1000); 35 Console.WriteLine("lalalala...."); 36 37 return;//---------------------------------------------------------------------------------------------------- 38 var cl = new {name="xiang",age=21}; 39 Console.WriteLine(cl.name); 40 return;//----------------------------------------------------------------------------------------------------- 41 //调用func 调用func 的直接好处就是 让你连委托声明 那句都省了 42 //说白了就是你传一段代码进来 我来执行 ,那么你传的这段代码就是参数 。你只需要把方法原型作为形参定义好 43 //感觉完全一锅写 有点类似于脚本语言的写法 44 //上面是lambda写法 下面是 匿名委托写法 45 callDel((num1, num2) => { 46 return num1 + num2; 47 }); 48 callDel((num1, num2) => { 49 return num1 - num2; 50 }); 51 52 callDel(delegate (int num1, int num2) { 53 return num1 * num2; 54 }); 55 56 MyDele d2 = delegate () 57 { 58 Console.WriteLine("call myDel2...."); 59 return 0; 60 }; 61 d2(); 62 63 MyDele d3 = new MyDele( 64 delegate { 65 Console.WriteLine("call myDel3...."); 66 return 0; 67 }); 68 d3(); 69 70 return;//----------------------------------------------------------------------------------------------- 71 //异步回调 72 MyDele d1 = new MyDele(() => { 73 //MessageBox.Show("mydel process"); 74 Console.WriteLine("mydel start"); 75 Thread.Sleep(2000); 76 Console.WriteLine("mydel end"); 77 return new Random().Next(); 78 }); 79 //d1.Invoke(); 80 81 IAsyncResult iars= d1.BeginInvoke((iar) => 82 { 83 //委托内容执行完成 后的回调 84 85 //iar 可以理解为特定的线程的句柄 进行回溯的 找到我们当初调用的 那个方法 86 //从而获取到 方法执行的结果 ,endinvolve 代表实质性的异步调用结束 可获得实实在在的执行结果 87 //既然执行到这里了 那么自然代表可以正常endinvoke了。 88 int rdmResult = d1.EndInvoke(iar); 89 Console.WriteLine("iar call back state :" + iar.AsyncState.ToString()); 90 Console.WriteLine("iar call back rst is :{0}",rdmResult); 91 }, "ss"); 92 93 //执行到这里 你无法确定能否 IsCompleted 啊 ,如果强行endinvoke 不就市区异步的意义了么, 94 //d1.EndInvoke(iars); 95 96 //比如这里我们等待3秒钟 没有执行完成 就结束线程 97 98 //wait one 就是阻塞主线程 把时间片完全让给 异步委托去执行 ,等待异步委托执行完成 。也是一种失去异步的意义的一种方式 99 //waitone 的时间 并不代表一定需要执行那么长时间,如果不带时间参数表示等待直至异步线程完成 100 iars.AsyncWaitHandle.WaitOne(); 101 Console.WriteLine("wait one 1000"); 102 //Thread.Sleep(3000); 103 //if (iars.IsCompleted) 104 // Console.WriteLine("mydel is complete"); 105 //else 106 //{ 107 // Console.WriteLine("mydel is not complete"); 108 //} 109 return;//--------------------------------------------------------------------------------------------------- 110 //空参数 的lambda 委托写法 去掉action 一样的效果 111 Thread t1 = new Thread(new ThreadStart( new Action(()=> 112 { 113 MessageBox.Show("t1 process"); 114 }))); 115 t1.Start(); 116 return;//----------------------------------------------------------------------------------------------------- 117 //用lambda的方式来写事件绑定 118 button2.Click += new EventHandler((sender2, e2) => 119 { 120 MessageBox.Show("hellow"); 121 }); 122 123 //Func 是一个带返回值形式 委托 ,就是微软新搞的一种花样 就是委托 124 //也可用lambda 的方式来写 125 List<string> strArr = new List<string>() { 126 "xiang", 127 "zhang", 128 "chen" }; 129 //var sel = strArr.Where(wheretest); 130 var sel = strArr.Where((r) => 131 { 132 if (r.Contains("g")) 133 return true; 134 else 135 return false; 136 }); 137 138 //lamda 方式的action 139 sel.ToList().ForEach(i => 140 { 141 Console.WriteLine(i); 142 }); 143 144 return;//----------------------------------------------------------------------------------------------------- 145 List<int> arr = new List<int>(); 146 arr.Add(23); 147 arr.Add(45); 148 arr.Add(22); 149 arr.ForEach((i) => 150 { 151 Console.WriteLine(i + ""); 152 }); 153 }
每次看都有不一样的东西,看山不是山 ,人生就是不断的学习。以前以为异步调用就是简单的分一个通道来做事情 ,还真不是那么简单
1 mydel d; 2 private void button3_Click(object sender, EventArgs e) 3 { 4 5 d = new mydel(deldo); 6 Console.WriteLine("aaa"); 7 //注意下面的d.BeginInvoke(null,null);并不一定要传入asyncCallBack ,根据你情况定 , 8 //比如你不需要得到异步调用的结果 (那还不如task.run() ? thread.start()? 9 //注意 注意 注意 再次说明 这个asynCallBack 在异步方法调用完成后 才会执行 ,仅仅是一个获取结果用 并无特别意思 10 11 //IAsyncResult ar= d.BeginInvoke(null,null); 12 //deldoend这个方法只有结束时才会调 ,只是相当于结束时候的一个通知 并没有其他意思 13 //如果不这样写 你就无法确定调用何时结束,当然你也可以 在begininvoke 后 同步做一些其他事, 14 //在最终的时候使用ar.synchandle.waitOne 等待调用结束 ,由此来做到不同线程的同步 15 IAsyncResult ar = d.BeginInvoke(deldoEnd, "hhh"); 16 //hhh为你想自定义传入end方法里的参数 end方法里使用ar.asyncState获取 17 Console.WriteLine("bbb"); 18 19 //Thread.Sleep(4000); 20 //Console.WriteLine("rstttt"+d.EndInvoke(ar)); 21 22 } 23 24 public int deldo() 25 { 26 Console.WriteLine("ccc"); 27 Thread.Sleep(3000); 28 Console.WriteLine(555); 29 return 5; 30 } 31 32 public void deldoEnd(IAsyncResult ar) 33 { 34 Console.WriteLine("ddd"); 35 int rest = d.EndInvoke(ar); 36 Console.WriteLine(ar.AsyncState.ToString()); 37 Console.WriteLine(rest); 38 } 39 40 delegate int mydel();
又是一些新的Task特性的使用方式,还是线程只不过换了种方式:
https://www.cnblogs.com/lonelyxmas/p/9509298.html