博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
多线程编程学习笔记——线程同步(二)
阅读量:7157 次
发布时间:2019-06-29

本文共 5668 字,大约阅读时间需要 18 分钟。

 接上文 

四、使用AutoResetEvent

1. 使用AutoResetEvent类来实现从一个线程向另一个线程发出通知。

2.代码如下

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading; //引入线程using System.Diagnostics;namespace ThreadSynchronousDemo{    class Program    {        static AutoResetEvent autoResetWork = new AutoResetEvent(false);        static AutoResetEvent autoResetMain = new AutoResetEvent(false);        static void Main(string[] args)        {            Console.WriteLine("开始,AutoResetEvent 同步");                       string threadName = "线程 1";                         var t = new Thread((() => working(threadName, 10)));                t.Start();            Console.WriteLine("开始,第一次工作");             autoResetWork.WaitOne();//万事俱备只欠东风,事情卡在这里了,            Console.WriteLine("第一次工作完成");            Console.WriteLine("主线程操作,准备发信号");            Thread.Sleep(TimeSpan.FromSeconds(5));            //发信号,说明值已经被写进去了。这里的意思是说Set是一个发信号的方法。            autoResetMain.Set();            Console.WriteLine("现在运行第二次工作。");            autoResetWork.WaitOne();            Console.WriteLine("第二次工作完成");            Console.Read();        }         static void working(string name,int seconds)        {            Console.WriteLine("{0} 开始运行工作", name);            Thread.Sleep(TimeSpan.FromSeconds(seconds));            Console.WriteLine("{0}  正在工作。。。。。。",              name);            //发信号,说明值已经被写进去了。这里的意思是说Set是一个发信号的方法。            autoResetWork.Set();            Console.WriteLine("等待主线程完成工作,并发出信号");            autoResetMain.WaitOne();            Console.WriteLine("主线程发来信号,开始第二次工作");            Thread.Sleep(TimeSpan.FromSeconds(seconds));            Console.WriteLine("{0} 第二次工作正在进行中。。。。。", name);            autoResetWork.Set();        }    }}

3.程序运行结果,如下图。

 

         以上程序中,我们定义了两个AutoResetEvent实例。其中一个是从子线程往主线程发信号 ,另一个是主线程往子线程发信号。我们在构造AutoResetEvent时,传入了false,定义了这两个实例的初始状态unsignaled。这个状态下,任何线程调用这两个实例的WaitOne方法将会被阻塞,直到我们调用了Set方法。如果我们在构造的时候传入了true,则这两个实例的初始状态是singnaled,则线程调用WaitOne则会被立即处理。

 

五、使用ManualResetEventSlim类

1. 使用ManualResetEventSlim在线程间传递信号。

 2.代码如下

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading; //引入线程using System.Diagnostics; namespace ThreadSynchronousDemo{    class Program    {        static ManualResetEventSlim manuResetWork = new ManualResetEventSlim(false);              static void Main(string[] args)        {            Console.WriteLine("开始,ManualResetEventSlim 同步");                       string threadName = "线程 1";            string threadName2 = "线程 2";             string threadName3 = "线程 3";            var t = new Thread((() => working(threadName, 3)));            var t2 = new Thread((() => working(threadName2, 6)));            var t3 = new Thread((() => working(threadName3, 12)));            t.Start();            t2.Start();            t3.Start();            Thread.Sleep(TimeSpan.FromSeconds(5));            Console.WriteLine("开始,打开 线程工作大门");            manuResetWork.Set(); //发信号            Thread.Sleep(TimeSpan.FromSeconds(3));            manuResetWork.Reset();                       Console.WriteLine("线程工作大门,关闭");                     Thread.Sleep(TimeSpan.FromSeconds(10));            Console.WriteLine("打开线程工作大门第二次打开了");            manuResetWork.Set(); //发信号            Thread.Sleep(TimeSpan.FromSeconds(3));            manuResetWork.Reset();            Console.WriteLine("线程工作大门,又关闭了");            Console.Read();        }        static void working(string name,int seconds)        {            Console.WriteLine("{0} 休息", name);            Thread.Sleep(TimeSpan.FromSeconds(seconds));            Console.WriteLine("{0}  等待打开线程运行的大门",              name);            manuResetWork.Wait();            Console.WriteLine("线程运行的大门打开了,{0} 进行工作", name);               }    }}

3.程序运行结果,如下图。

      当主程序启动时,首先创建ManualResetEvenSlim类的一个实例,然后启动了三个线程,等待事件信号通知它们继续工作。

      ManualResetEvenSlim的工作方式有点像人群通过大门,而AutoResetEvent事件像一个旋转门,一次只能通过一人。

      ManualResetEvenSlim打开了大门,一直保持打开,直到调用了Reset方法。直到再次调用Set方法打开 大门。

 

六、使用CountDownEvent类

1. 使用CountDownEvent信号类来等待直到一定数量的操作完成。

2.代码如下

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading; //引入线程using System.Diagnostics; namespace ThreadSynchronousDemo{    class Program    {        static CountdownEvent CountDownWork = new CountdownEvent(2);              static void Main(string[] args)        {            Console.WriteLine("开始,CountdownEvent 同步");                   var t = new Thread((() => working("第 1 个工作线程任务", 3)));            var t2 = new Thread((() => working("第 2 个工作线程任务", 6)));            //var t3 = new Thread((() => working("第 3 个工作线程任务", 12)));            t.Start();            t2.Start();            //t3.Start();            Thread.Sleep(TimeSpan.FromSeconds(5));            Console.WriteLine("开始,线程工作计数");            CountDownWork.Wait();                       Console.WriteLine("计数完成,2个工作 已经完成!");            //如果把上面代码注释的第三个线程还原,释放对象,可以造成第三个线程的抛出错误            CountDownWork.Dispose();                 Console.Read();        }         static void working(string message,int seconds)        {            Console.WriteLine("工作前休息 {0}",DateTime.Now.Second);            Thread.Sleep(TimeSpan.FromSeconds(seconds));            Console.WriteLine(message);                      CountDownWork.Signal();            Console.WriteLine("发出计数信号, 工作已经完成一项");              }    }}

3.程序运行结果如下图。

     程序启动时,创建了一个CountDownEven实例,在构造中指定了,当两个操作完成时给出信号。然后我们启动了两个线程进行工作,当第二个线程完成操作时,主线程从等待CountDownEvent的状态中返回并继续工作。这个类使用场景是,主线程需要等待多个线程完成工作之后,才能继续的情形。

缺点:必须要等待指定数量的线程全部完成工作,否则就一直会等待,请确保使用CountDownEvent时,所有线程完成工作后,都要调用Signal方法。

说明:

1)  把上面代码中注释的第三个线程的代码,还原则会出现以下错误。

 

2) 如果把 第三个线程启用,同时把 CountDownWork.Dispose();注释,则会出现以下错误信息。

 

 

 

 

 

转载地址:http://dmegl.baihongyu.com/

你可能感兴趣的文章
【转载】不想提拔你,就是因为你只想把工作做好
查看>>
【原创】HBase 基础知识
查看>>
快捷支付
查看>>
非对称加密原理解析
查看>>
菜菜鸟Zend Framework 2 不完全学习涂鸦(六)-- 数据库和模式
查看>>
Filter过滤器
查看>>
Netperf 做网络性能测试
查看>>
Storyboard教程-创建Tab Bar控制器和Web视图
查看>>
<转>解读mysql主从配置及其原理分析(Master-Slave)
查看>>
wordpress 循环重定向的问题
查看>>
功能强大,完全兼容树莓派,兼容树莓派cubieboard的开发板
查看>>
Thymeleaf模板性能测试
查看>>
Redis 高可用性实践
查看>>
java异常
查看>>
提高PHP网站安全性的5个技巧
查看>>
表中有A B C三列,用SQL语句实现:当A列大于B列时选择A列否则选择B列,当B列大于C列时选择B列否则选C...
查看>>
CentOS下du 和 df 的区别
查看>>
细节是魔鬼
查看>>
maven 搭建私服
查看>>
关于 Python 的升级,真不是那么好升的。。。
查看>>