当前位置:  编程技术>.net/c#/asp.net

深入多线程之:Wait与Pulse的使用详解

    来源: 互联网  发布时间:2014-10-20

    本文导语:  Signaling with Wait and Pulse(等待和暂停的信号) 早期谈论过等待事件句柄(调用Wait的线程在没有收到另一个线程的通知前会一直阻塞)。 Monitor借助它的静态方法Wait,Pulse,PulseAll提供了一个更给力的信号构造,使用这些方法和lock...

Signaling with Wait and Pulse(等待和暂停的信号)

早期谈论过等待事件句柄(调用Wait的线程在没有收到另一个线程的通知前会一直阻塞)。

Monitor借助它的静态方法Wait,Pulse,PulseAll提供了一个更给力的信号构造,使用这些方法和lock语句,你可以自己实现AutoResetEvent,ManualResetEvent和Semaphore。甚至WaitHandle的WaitAll和WaitAny方法了。

怎样使用Wait 和Pulse ?

1:定义一个同步对象,例如:

  Readonly object _locker=new object();

2:定义自己的阻塞条件中的字段。

  bool _go 或者 int _semaphoreCount;

3:当你想要阻塞的时候,包含下面的代码

  lock(_locker)

         while() //比如while (_go ==false)

                   Monitor.Wait(_locker);    //满足阻塞条件,开始阻塞。

4:当想要改变阻塞条件的时候,包含下面的代码:

     lock(_locker)

{

    //,比如_go=true;

         Monitor.Pulse(_locker); //或者: Monitor.PulseAll(_locker); //通知等待队列中的线程锁定对象状态的更改。

}

这个模式可以让你随时随地等待线程。下面是一个例子,worker线程在_go 字段变成true之前会一直等待。

代码如下:

static readonly object _locker = new object();
        static bool _go;

        internal static void Main()
        {
            new Thread(Work).Start(); //新线程会被阻塞,因为_go == false
            Console.ReadLine(); //等待用户输入

            lock (_locker)
            {
                _go = true; //改变阻塞条件
                Monitor.Pulse(_locker); //通知等待的队列。
            }
        }

        static void Work()
        {
            lock (_locker)
            {
                while (!_go) //只要_go字段是false,就等待。
                    Monitor.Wait(_locker); //在等待的时候,锁已经被释放了。
            }

            Console.WriteLine("被唤醒了");
        }


为了线程安全,确保所有共享的字段在读取的时候都加锁了。

Work方法会一直阻塞,等待_go字段变成true,Monitor.Wait方法按顺序的做了以下的操作。

1:释放锁_locker;

2:阻塞锁,直到_locker 是”pulsed”。

3:重新在_locker 上获取锁,如果锁已经被其他线程获得,那么线程开始阻塞,直到锁变得可用为止。

代码如下:

lock(_locker)
{
    While(!_go)
        Monitor.Wait(_locker); //释放锁
    //已经重新获取了锁。
}


如果我们抛弃该模式,例如移除while循环。_go字段和ReadLine方法等:
代码如下:

static object _locker = new object();

        internal static void Main()
        {
            new Thread(Work).Start();
            lock (_locker) Monitor.Pulse(_locker);
        }

        static void Work()
        {
            lock (_locker) Monitor.Wait(_locker);
            Console.WriteLine("被唤醒了");
        }


那么程序运行的结果又如何呢?

实际上输出是不确定的,有可能你不能显示“被唤醒了”。

主要原因是主线程和Work线程之间存在着竞争关系,如果Wait方法先执行,那么可以正常显示,但是如果Pulse方法先执行,pulse就会丢失,worker线程就会永远的等待。这种行为和AutoResetEvent不同,AutoResetEvent的Set方法有一种记忆的效果,所以即使它在WaitOne方法前调用,它仍然有效。


但是Pulse没有记忆功能,因为你希望自己实现记忆功能,就像我们之前使用_go 标志一样,

这就是为什么Wait和Pulse是通用的原因:使用一个boolean 标志,我们可以实现AutoResetEvent的功能,使用一个integer标志,我们可以实现 CountdownEvent,Semaphore.使用更复杂的结构,我么可以写一些更复杂的构造。


    
 
 

您可能感兴趣的文章:

  • 如何深入了解线程
  • 深入多线程之:深入分析Interlocked
  • 深入多线程之:解析线程的交会(Thread Rendezvous)详解
  • 深入分析父子线程、进程终止顺序不同产生的结果
  • 深入多线程之:深入生产者、消费者队列分析
  • 深入多线程之:双向信号与竞赛的用法分析
  • 深入多线程之:用Wait与Pulse模拟一些同步构造的应用详解
  • 深入Java线程中断的本质与编程原则的概述
  • 深入SQLite多线程的使用总结详解
  • 深入理解线程安全与Singleton
  • 深入探讨linux下进程的最大线程数、进程最大数、进程打开的文件数
  • Java 多线程同步 锁机制与synchronized深入解析
  • 深入Sqlite多线程入库的问题
  • 深入多线程之:Reader与Write Locks(读写锁)的使用详解
  • 深入Android线程的相关问题解惑
  • 深入java线程池的使用详解
  • 深入Android Handler与线程间通信ITC的详解
  • Java线程中断的本质深入理解
  • Android开发笔记之:深入理解多线程AsyncTask
  • 深入多线程之:内存栅栏与volatile关键字的使用分析
  • 深入JDBC sqlserver连接写法的详解
  • 深入mysql YEAR() MONTH() DAYOFMONTH()日期函数的详解
  • 深入SQLServer中ISNULL与NULLIF的使用详解
  • 深入C++可见性与生命期的区别详解
  • 深入mysql并发插入优化详解
  • 深入android Unable to resolve target 'android-XX'详解
  • 深入MYSQL字符数字转换的详解
  • 深入SQL Server中定长char(n)与变长varchar(n)的区别详解
  • 深入C#任务管理器中应用程序选项隐藏程序本身的方法详解
  • 深入Windows下的回车是回车换行(rn)还是换行回车(nr)的详解
  • 深入分析NTFS中文件被锁定导致Process.Start失败的详解
  •  
    本站(WWW.)旨在分享和传播互联网科技相关的资讯和技术,将尽最大努力为读者提供更好的信息聚合和浏览方式。
    本站(WWW.)站内文章除注明原创外,均为转载、整理或搜集自网络。欢迎任何形式的转载,转载请注明出处。












  • 相关文章推荐
  • 深入Ref,Out的理解及其使用
  • 基于c中使用ftruncate()前需要fflush(),使用后需要rewind()的深入探讨
  • 深入C#中使用SqlDbType.Xml类型参数的使用详解
  • 深入Main函数中的参数argc,argv的使用详解
  • 深入ORACLE变量的定义与使用的详解
  • 深入解析c#中枚举类型的定义与使用
  • 深入VC回调函数的使用详解
  • 深入Android MediaPlayer的使用方法详解
  • SQL Server 索引结构及其使用(一)--深入浅出理解索引结构第1/4页
  • 深入C++中inline关键字的使用
  • 深入uCOS中全局变量的使用详解
  • Android中使用PULL方式解析XML文件深入介绍
  • 深入Java对象的地址的使用分析
  • 深入分析C++中deque的使用
  • 函数中使用require_once问题深入探讨 优雅的配置文件定义方法推荐
  • Mysql的游标的定义使用及关闭深入分析
  • 深入C#字符串和享元(Flyweight)模式的使用分析
  • oracle 索引不能使用深入解析
  • 深入dom4j使用selectSingleNode方法报错分析
  • 深入sizeof的使用详解
  • Docker支持更深入的容器日志分析
  • 关于《深入浅出MFC》
  • Linux有没有什么好的高级的书,我要深入,
  • 深入理解linux内核
  • [100分]有没有关于binutils的深入的资料?或者深入底层的资料?
  • 深入理解PHP内核 TIPI
  • 想深入学习Java应该学习哪些东西
  • 深入ORACLE变量的定义与使用的详解 iis7站长之家
  • 想要深入学习LINUX该学什么?
  • 100分求:哪儿有《深入理解linux内核》可供下哉!
  • 如何深入Linux的内核学习?


  • 站内导航:


    特别声明:169IT网站部分信息来自互联网,如果侵犯您的权利,请及时告知,本站将立即删除!

    ©2012-2021,,E-mail:www_#163.com(请将#改为@)

    浙ICP备11055608号-3