【编写高质量代码C#】建议72:在线程同步中使用信号量
1.使用信号机制提供线程同步的一个简单例子
AutoResetEvent autoResetEvent = new AutoResetEvent(false); private void button1_Click(object sender, EventArgs e) { Control.CheckForIllegalCrossThreadCalls = false; Thread tWork = new Thread(() => { label1.Text = "线程启动..." + Environment.NewLine; label1.Text += "开始处理一些实际的工作" + Environment.NewLine; //省略工作代码 label1.Text += "我开始等待别的线程给我信号,才愿意继续下去" + Environment.NewLine; autoResetEvent.WaitOne(); label1.Text += "我继续做一些工作,然后结束了!"; //省略工作代码 }); tWork.IsBackground = true; tWork.Start(); } private void button2_Click(object sender, EventArgs e) { //将事件状态设置为终止状态,允许一个或多个等待线程继续 autoResetEvent.Set(); }
以上例子中,点击按钮1执行到autoResetEvent.WaitOne()不再往下,点击按钮2才会继续往下执行。
2.AutoResetEvent和ManualResetEvent的区别:
使用AutoResetEvent,autoResetEvent.Set()只能使一个线程继续,而ManualResetEvent,manualResetEvent.Set()可使多个线程继续执行。
例子如下:
private void button2_Click(object sender, EventArgs e) { //将事件状态设置为终止状态,允许一个或多个等待线程继续 //autoResetEvent.Set(); manualResetEvent.Set(); } private void button3_Click(object sender, EventArgs e) { Control.CheckForIllegalCrossThreadCalls = false; StartThread1(); StartThread2(); } private void StartThread1() { Thread tWork1 = new Thread(() => { label1.Text = "线程1启动..." + Environment.NewLine; label1.Text += "开始处理一些实际的工作" + Environment.NewLine; //省略工作代码 label1.Text += "我开始等待别的线程给我信号,才愿意继续下去" + Environment.NewLine; //autoResetEvent.WaitOne(); manualResetEvent.WaitOne(); label1.Text += "我继续做一些工作,然后结束了!"; //省略工作代码 }); tWork1.IsBackground = true; tWork1.Start(); } private void StartThread2() { Thread tWork2 = new Thread(() => { label2.Text = "线程2启动..." + Environment.NewLine; label2.Text += "开始处理一些实际的工作" + Environment.NewLine; //省略工作代码 label2.Text += "我开始等待别的线程给我信号,才愿意继续下去" + Environment.NewLine; //autoResetEvent.WaitOne(); manualResetEvent.WaitOne(); label2.Text += "我继续做一些工作,然后结束了!"; //省略工作代码 }); tWork2.IsBackground = true; tWork2.Start(); }
3.模拟网络通信
private void button4_Click(object sender, EventArgs e) { Control.CheckForIllegalCrossThreadCalls = false; Thread t = new Thread(() => { while (true) {
//原理:没隔3秒检测接收,若未接收到a.Set(),则离线 bool re=a.WaitOne(3000); if (re) { label3.Text = string.Format("时间:{0},{1}", DateTime.Now.ToString(), "在线"); } else { label3.Text = string.Format("时间:{0},{1}", DateTime.Now.ToString(), "离线"); } } }); t.IsBackground = true; t.Start(); } private void button5_Click(object sender, EventArgs e) { a.Set(); }