注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

还东国的博客

行之苟有恒,久久自芬芳

 
 
 

日志

 
 

Linux中信号假唤醒的一点体会  

2013-12-06 09:19:57|  分类: LINUX编程 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

Linux中信号假唤醒的一点体会

如果大家经常在多线程的情况下编程就会有这样的体会,多线程的调度机制(在同优先级下)是无序的,是随机的。

可是一般在实际应用中,经常需要他们是有序的,按步骤执行的,这就出现了同步机制,但这也带来了一定的系统开销和可怕的后果(如死锁)。

LINUX下在使用条件变量时,就要非常注意,在陈硕的博客里:

http://www.cppblog.com/Solstice/archive/2013/09/09/203094.html

https://github.com/chenshuo/recipes/blob/master/thread/test/Waiter_test.cc

介绍了原理 机制以及经常使用的八种情况。所以这里就不再重复轮子,这里只是说明一下,为什么在判断标记变量时,一定要采用while而不是使用if,如下:

  void wait() override

  {

    pthread_mutex_lock(&mutex_);

    if (!signaled_)

    {

      pthread_cond_wait(&cond_, &mutex_);

    }

    pthread_mutex_unlock(&mutex_);

  }

 

  void wait() override

  {

    pthread_mutex_lock(&mutex_);

    while (!signaled_)

    {

      pthread_cond_wait(&cond_, &mutex_);

    }

    pthread_mutex_unlock(&mutex_);

  }

诚如上面说的,线程的调度是随机的,无序的,先以if为例,所以可能就会有下面这种情况:if判断是条件变量不符合情况,进入等待,然后一个假的信号发了出来,这时候,程序就应该继续执行下去,但是,这是不符合程序的意愿的,但是如果你换成while,程序就会继续进行下一个循环,判断条件变量仍然是不符合情况,继续进入下一次等待。不会执行锁后面的代码。

当然 ,这也有开销上的代价了,前面讲过。但是一般情况下,什么时候儿会出现信号的假得唤醒状态呢?在多线程的情况下,信号的唤醒一般是唤醒多个线程的(也就是常说的惊群现象)。摘一段网上的说明:

linux中,pthread_cond_wait底层是futex系统调用。在linux中,任何慢速的阻塞的系统调用当接收到信号的时候,就会返回-1,并且设置errnoEINTR。在系统调用返回前,用户程序注册的信号处理函数会被调用处理。

 

:什么有样的系统调用会出现接收信号后发挥EINTR呢?

慢速阻塞的系统调用,有可能会永远阻塞下去的那种。当接收到信号的时候,认为是一个返回并执行其他代码的一个时机。

信号的处理也不简单,因为有些慢系统调用被信号中断后是会自动重启的,所以我们通常需用siginterrupt(signo, 1)来关闭重启或者在用sigaction安装信号处理函数的时候取消SA_RESTART标志,之后就可以通过判断信号的返回值是否是-1errno是否为EINTR来判断是否有信号抵达。

如果关闭了SA_RESTART的一些使用慢速系统调用的应用,一般都采用while()循环,检测到EINTR后就重新调用。 

while(1)

{

   int ret = syscall();

   if(ret<0 && errno==EINTR)

       continue;

   else

       break;

}

但是,对于futex这种方法不行,因为futex结束后,再重新运行的过程中,会出现一个时间窗口,其他线程可能会在这个时间窗口中进行pthread_cond_signal,这样,再进行pthread_cond_wait的时候就丢失了一次条件变量的变化。解决方法就是在pthread_cond_wait前检查条件变量,也就是

pthread_mutex_lock();

while(condition_is_false)

    pthread_cond_wait();

pthread_mutex_unlock();

pthread_cond_broadcast

实际上,不仅仅信号会导致假唤醒,pthread_cond_broadcast也会导致假唤醒。加入条件变量上有多个线程在等待,pthread_cond_broadcast会唤醒所有的等待线程,而pthread_cond_signal只会唤醒其中一个等待线程。这样,pthread_cond_broadcast的情况也需要在pthread_cond_wait前使用while循环来检查条件变量。

那么什么是futex系统调用呢?下一篇转载的的博客会详细说明。

  评论这张
 
阅读(651)| 评论(0)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017