简单的线程处理 及同步:
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;
}
}
一些关于匿名委托 和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();