`
lijuanabc
  • 浏览: 119904 次
社区版块
存档分类
最新评论

随笔之POSIX cond和Windows同步对象Event的讨论

 
阅读更多
一 缘由
最近在实现一个线程池的时候,需要用到POSIX中的cond和mutex进行线程间等待和同步,功能类似MS的同步对象Event。
发现cond和mutex的连用还是挺不人性化的。说实话,MS在同步对象的API上,做得还是相当不错,文档也很清晰。
Anyway,既然只能使用POSIX,就只能将就了。
我这个线程池在实现中碰到以下2个问题:
1 有n个线程等待一个事件。当有任务添加的时候,需要触发其中一个线程启动。
2 当线程池退出时,我需要触发所有线程启动,并检测退出标志,从而退出线程循环。
这个问题其实比初看上去要复杂,下面来分析
二 Windows上的实现
先介绍下Event同步对象,
HANDLE CreateEvent(
LPSECURITY_ATTRIBUTES lpEventAttributes,// pointer to security attributes
BOOL bManualReset, // flag for manual-reset event
BOOL bInitialState, // flag for initial state
LPCTSTR lpName // pointer to event-object name
);
第二个参数:bManualReset表示该对象为人工还是自动变量。我们重点就是讨论这个,该值决定以下几个特点:
  • 当Event为人工变量时,一旦被触发,则一直保持触发状态,触发调用ResetEvent重置状态。假设该值被触发,那么调用WaitXXX函数的所有线程都不应该阻塞在该事件上。
  • 当Event为自动变量时,一旦被触发,如果有线程在等,那么只会启动其中一个线程(只会启动一个线程,因为该值在启动一个线程后会重置)。如果没有线程在等,那么该值一直保持触发状态
从上面Event的介绍来看,自动变量一次触发一个线程,而人工变量一直保持触发状态。不过系统并没有说如果一个线程很快SetEvent并又ResetEvent的话,Wait的线程会如何。
我们先看看在MS平台上该如何解决上面的问题:
最普遍的方法就是:
1 创建一个Auto的Event,这个Event用来触发工作线程从任务队列中获取任务
2 创建一个Manual的Event,这个Event用来触发所有工作线程退出
然后利用WaitForMultiObject来等待这两个Event。
Problem solved!!
三 Linux的实现
Linux上最大的问题是没有WaitForMultiObject这样的函数,那么我们只能创建一个包含Mutex和Cond的结构体来充当Event
由于cond的触发有两个函数,特性分别是:
  • pthread_cond_signal:保证多个线程调用pthread_cond_wait等待的时候只有一个线程能够返回。
  • pthread_cond_broadcast:保证多个线程等待的时候,都能返回。
我们在使用cond实现类型的触发和等待的时候,代码经常如下所示:
void Wake(allThreads?)
{
Mutex lock
set condition = 1;
if(allThreads)
pthread_cond_broadcast //触发所有线程
else
pthread_cond_signal //触发单个线程
Mutex unlock
}
void Wait()
{
Mutex lock
while(condition != 1)
{
pthread_cond_wait(cond,&mutex); //cond的wait需要传入一个Mutex做参数,wait函数内部会unlock这个mutex
}
Mutex unlock
}
为什么在Wait的时候需要有一个while循环来检测condition是否满足条件呢?最主要有两个原因:
  • cond本身的机制导致。如果cond触发(不论是signal还是broadcast)的时候,没有线程在wait的话,那么线程以后wait将无法捕获这个触发。这和Windows的Event截然不同。自动变量的Event如果触发后,即使当时没有线程在等待,如果以后有线程等待的话,那么也是可以返回的。而posix的cond没有实现这个功能。所以我们只能自己加condition来做判断。如果condition为1,则无需等待。
  • pthread_cond_wait的返回有可能是因为信号的原因导致,这个时候conditon并不满足,所以这里也需要一个while循环
根据上面的基础知识,我们目前已满足的是:
  • cond_signal能并且只能触发一个线程起来
  • cond_broadcast能触发所有线程起来
但是问题随之而来,因为现在只有一个condition,什么时候置为零呢?必须满足两个条件:
  • 对于触发单个线程的来说,因为只有一个启动,所以当它启动后,需要把condtion置为零,表示自己已经消费了这个条件。
  • 对于所有启动的来说,只有最后一个线程退出等待的时候需要把conditon置为零,表示所有人都消费了这个条件。
解决办法就是使用waiter计数,最终修改后的代码如下:
void Wake(allThreads?)
{
Mutex lock
if(condtion == -1 || condition == 1) //为什么要加这样的判断?
{
Mutex unlock
return;
}
if(allThreads)
{
set condition = -1; //表示等待多个
pthread_cond_broadcast //触发所有线程
}
else
{
set condition = 1;
pthread_cond_signal //触发单个线程
}
Mutex unlock
}
void Wait()
{
Mutex lock
++waiters;
while(condition == 0)
{
pthread_cond_wait(cond,&mutex); //cond的wait需要传入一个Mutex做参数,wait函数内部会unlock这个mutex
}
if(--waiters == 0)
condition = 0;
Mutex unlock
}
我们可以捋一下各种case:
  • 只触发单个线程的话,没有问题。这个是最简单的。
  • 触发多个线程的话,如果在触发后并且在旧的等待线程未全部返还之前,如果又有新线程调用wait的话,实际上是不会被阻塞的。
Wake函数前面红色字体的代码干什么用?
就怕调用者先调用了Wake(true),旋即又调用了Wake(false),导致condtion值混乱。通过判断condition是否已经触发,我们可以避免出问题。
四:结论
POSIX的cond和mutex联合使用,总感觉效率上会有损失。因为cond_wait返还后还是需要竞争mutex,实际上Wait函数在用户空间是串行执行的。
不知道Windows的Event是如何实现的?
上面的代码应该还不是很完善,有问题再修改,不知道您看出什么毛病了吗?
分享到:
评论

相关推荐

    windows posix 线程库

    windwos 下的posix pthread库,可以直接移植Linux下的多线程代码,到window运行

    posix pthread windows 实现

    详见: https://www.sourceware.org/pthreads-win32/

    POSIX Threads for Windows-开源

    Windows的POSIX线程也称为“ pthreads-win32”,实现了Single Unix Specification版本3中与线程相关的API的很大一部分。一致性和质量是此成熟库的高度优先事项。 开发工作始于1998年,并一直持续进行,并做出了许多...

    POSIX Threads (pthreads) for Win32

    Pthreads-win32是一个Windows下使用的开源POSIX线程库,当前最新版本为2.9.1

    POSIX多线程程序设计.pdf

    然后讨论了一些高级话题,包括属性对象、线程私有数据和实时调度。此外,本书还讨论了调度的问题,并给出了避免错误和提高性能等问题的有价值的建议。本书使用了大量注释过后 实例来解释实际的概念,并包括Pthreads...

    POSIX多线程程序设计

    然后讨论了, 一些高级话题,包括属性对象、线程私有数据和实时调度。此外,本书还讨论了调度的问, 题,并给出了避免错误和提高性能等问题的有价值的建议。本书使用了大量注释过的实例, 来解释实际的概念,并包括...

    POSIX多线程程序设计中文版

    书首先解释了线程的基本概念,包括异步编程、线程的生命周期和同步机制;然后讨论了 一些高级话题,包括属性对象、线程私有数据和实时调度。此外,本书还讨论了调度的问 题,并给出了避免错误和提高性能等问题的有...

    深入浅出Linux环境编程(进程基础+IPC+POSIX+线程同步与互斥)配套资料

    深入浅出Linux环境编程(进程基础+IPC+POSIX+线程同步与互斥)配套资料

    timer.rar_POSIX Timer

    对POSIX timer的面向对象的封装。

    Programming with POSIX threads 第三章线程同步

    Programming with POSIX threads 第三章 线程同步 (英文版)非影印版

    posix官方相关文档

    POSIX Base Definitions.pdf POSIX Base Specifications, Issue 7.pdf POSIX Rationale (Informative).pdf POSIX Realtime and Embedded Application Support.pdf(IEEE std 1003.13-2003) POSIX Shell and ...

    Simple-Windows-Posix-Semaphore:一个简单的窗口 POSIX 信号量库

    POSIX 信号量允许进程和线程同步它们的动作。 信号量是一个整数,其值决不允​​许低于零。 可以对信号量执行两种操作:将信号量值加一 [ sem_post ]; 并将信号量值减一 [ sem_wait ]。 如果信号量的值当前为零,则...

    POSIX多线程设计

    本书深入描述了 IEEE人开放系统接口标准 POSIX 线程,通常称为Pthreads标准。本书首先解释了线程的基本概念,包括异步编程、线程的生命周期和同步...然后讨论了一些高级话题,包括属性对象,线程私有数据和实时调试。

    windows-kill:在Windows中通过PID发送信号进行处理,例如POSIX kill

    此功能在POSIX操作系统上很好用,但是在Windows中,不支持任何信号(即使SIGINT和SIGBREAK ,该节点在Windows中也受支持),并且将这些信号中的任何一个发送到Windows中的任何进程,将导致这些信号被立即杀死。...

    posix threads for win32源代码

    posix threads for win32源代码posix threads for win32源代码posix threads for win32源代码posix threads for win32源代码posix threads for win32源代码posix threads for win32源代码posix threads for win32源...

    posix多线程程序设计源码

    posix多线程程序设计源码 posix多线程程序设计源码 posix多线程程序设计源码 posix多线程程序设计源码

    node-posix-ext:fs和posix的Node.js模块流程的直接替代品,可在POSIX和Windows平台上提供其POSIX功能

    fs和posix的Node.js模块流程的替代品,可在POSIX和Windows平台上提供其POSIX功能。 动机 公开了POSIX API等。 其中有些是在Windows上实现的,有些则不是。 编写跨平台代码时,后者必须由其他代码包装,因为Node.js...

    Posix线程(经典)

    posix多线程相关的函数介绍,与POSIX多线程程序设计中文版一起看,相得益彰

    并行计算 + Posix

    对并行计算和Posix编程的入门教材,分两个部分:第一部分讲并行计算;第二部分讲Posix

Global site tag (gtag.js) - Google Analytics