设为首页收藏本站

郑州科技市场

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 1461|回复: 0
打印 上一主题 下一主题

[交流] 【§UNIX环境高级编程—线程同步之条件变量§系统】

[复制链接]
跳转到指定楼层
楼主
发表于 2013-7-17 11:15:59 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
【§UNIX环境高级编程—线程同步之条件变量§系统】
        条件变量变量也是出自POSIX线程标准,另一种线程同步机制。主要用来等待某个条件的发生。可以用来同步同一进程中的各个线程。当然如果一个条件变量存放在多个进程共享的某个内存区中,那么还可以通过条件变量来进行进程间的同步。

    每个条件变量总是和一个互斥量相关联,条件本身是由互斥量保护的,线程在改变条件状态之间必须要锁住互斥量。条件变量相对于互斥量最大的优点在于允许线程以无竞争的方式等待条件的发生。当一个线程获得互斥锁后,发现自己需要等待某个条件变为真,如果是这样,该线程就可以等待在某个条件上,这样就不需要通过轮询的方式来判断添加,大大节省了CPU时间。
    在互斥量一文中说过:互斥量是用于上锁,而不是用于等待;现在这句话可以加强为:互斥量是用于上锁,条件变量用于等待;
    条件变量声明为pthread_cond_t数据类型,在<bits/pthreadtypes.h>中有具体的定义。
1条件变量初始化和销毁
双击代码全选1
2
3
4
#include <pthread.h>   
int pthread_cond_init (pthread_cond_t *cond,const pthread_condattr_t *cond_attr) ;   
int pthread_cond_destroy (pthread_cond_t *cond);   
                                        两者的返回值都是:若成功则返回0,否则返回错误号



上面两个函数分别由于条件变量的初始化和销毁。
    和互斥量的初始化一样,如果条件变量是静态分配的,可以通过常量进行初始化,如下:
   pthread_cond_t mlock = PTHREAD_COND_INITIALIZER;  
    也可以通过pthread_cond_init()进行初始化,对于动态分配的条件变量由于不能直接赋值进行初始化,就只能采用这种方式进行初始化。那么当不在需要使用条件变量,释放底层空间之前,需要调用pthread_cond_destroy()销毁该条件所占用的资源。
2条件变量的使用
双击代码全选1
2
3
4
5
6
7
8
9
10
11
/*  等待条件变为真 */
int pthread_cond_wait (pthread_cond_t *cond,pthread_mutex_t *mutex);   
      
/* 限时等待条件为真 */
int pthread_cond_timedwait (pthread_cond_t *cond,pthread_mutex_t *mutex,const struct timespec *abstime);  http://www.lpxt.com      
/* 唤醒一个等待条件的线程.  */
int pthread_cond_signal (pthread_cond_t *cond);   
      
/* 唤醒等待该条件的所有线程 */
int pthread_cond_broadcast (pthread_cond_t *cond);



(1)pthread_cond_wait()函数用于等待条件被触发。该函数传入两个参数,一个条件变量一个互斥量,函数将条件变量和互斥量进行关联,互斥量对该条件进行保护,传入的互斥量必须是已经锁住的。调用pthread_cond_wait()函数后,会原子的执行以下两个动作:
将调用线程放到等待条件的线程列表上,即进入睡眠;
对互斥量进行解锁;
    由于这两个操作时原子操作,这样就关闭了条件检查和线程进入睡眠等待条件改变这两个操作之间的时间通道,这样就不会错过任何条件的变化。
    当pthread_cond_wait()返回后,互斥量会再次被锁住。
(2)pthread_cond_timedwait()函数和pthread_cond_wait()的工作方式相似,只是多了一个等待时间。等待时间的结构为struct timespec:
双击代码全选1
2
3
4
struct timespec{   
time_t  tv_sec    //Seconds.   
long    tv_nsec   //Nanoseconds.   
};



函数要求传入的时间值是一个绝对值,不是相对值,例如,想要等待3分钟,必须先获得当前时间,然后加上3分钟。
    要想获得当前系统时间的timespec值,没有直接可调用的函数,需要通过调用gettimeofday函数获取timeval结构,然后转换成timespec结构,转换公式就是:
双击代码全选1
2
timeSpec.tv_sec = timeVal.tv_sec;   
timeSpec.tv_nsec = timeVal.tv_usec * 1000;



所以要等待3分钟,timespec时间结构的获得应该如下所示:
双击代码全选1
2
3
4
5
6
7
8
9
10
struct timeval now;   
struct timespec until;   
gettimeofday(&now);//获得系统当前时间   
http://www.lpxt.com            
//把时间从timeval结构转换成timespec结构   
until.tv_sec = now.tv_sec;   
until.tv_nsec = now.tv_usec * 1000;   
      
//增加min   
until.tv_sec += 3 * 60;



如果时间到后,条件还没有发生,那么会返回ETIMEDOUT错误。
    从pthread_cond_wait()和pthread_cond_timewait(http://www.xitongshoucang.com)成功返回时,线程需要重新计算条件,因为其他线程可能在运行过程中已经改变条件。
    注意:pthread_cond_wait/pthread_cond_timewait函数的返回并不意味着条件的值一定发生了改变,必须重新检查条件的值。
    pthread_cond_wait/pthread_cond_timewait函数返回时,相应的互斥量将被当前线程锁定。即使是函数出错返回。
    一般一个条件表达式都是在一个互斥量的保护下被检查的。当条件表达式未被满足时,线程将仍然阻塞在这个条件变量上。当另一个线程改变了条件的值并向条件变量发出信号时,等待在这个条件变量上的一个线程或者所有线程被唤醒,接着都试图再次占有相应的互斥量。
    阻塞在条件变量上的线程被唤醒以后,直到pthread_cond_wait函数返回之前,条件的值都有可能发生变化。所以函数返回以后,在锁定相应的互斥量之前,必须重新测试条件变量。最后的测试方式是循环调用pthread_cond_wait函数,并把满足条件的表达式置为循环的终止条件。例如:
双击代码全选1
2
3
4
5
6
7
pthread_mutex_lock();   
      
while (condition_is_false)   
      
pthread_cond_wait();   
      
pthread_mutex_unlock();



注意:pthread_cond_wait函数是退出点,如果在调用这个函数时,已有一个挂起的退出请求,且线程允许退出,这个线程将被终止并开始执行善后处理函数,而这时和条件变量相关的互斥量仍将处在锁定状态。(即pthread_cond_wait失败返回,但仍然获得互斥量,在清理函数注意解开该互斥量)

分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
回复

使用道具 举报

*滑动验证:
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋|手机版|郑州二手手机|郑州二手电脑|郑州二手笔记本|郑州科技市场 ( 豫ICP备11013749号  

GMT+8, 2025-1-22 20:53 , Processed in 0.185033 second(s), 19 queries .

Powered by Discuz! X3.2

© 2001-2016 Comsenz Inc.

快速回复 返回顶部 返回列表