条件变量变量也是出自POSIX线程标准,另一种线程同步机制,。主要用来等待某个条件的发生。可以用来同步同一进程中的各个线程。当然如果一个条件变量存放在多个进程共享的某个内存区中,那么还可以通过条件变量来进行进程间的同步。

每个条件变量总是和一个互斥量相关联,条件本身是由互斥量保护的,线程在改变条件状态之间必须要锁住互斥量。条件变量相对于互斥量最大的优点在于允许线程以无竞争的方式等待条件的发生。当一个线程获得互斥锁后,发现自己需要等待某个条件变为真,如果是这样,该线程就可以等待在某个条件上,这样就不需要通过轮询的方式来判断添加,大大节省了CPU时间。

在互斥量一文中说过:互斥量是用于上锁,而不是用于等待;现在这句话可以加强为:互斥量是用于上锁,条件变量用于等待;

条件变量声明为pthread_cond_t数据类型,在中有具体的定义。

1、条件变量初始化和销毁

/* Initialize condition variable */

int pthread_cond_init (pthread_cond_t *__restrict __cond,

__const pthread_condattr_t *__restrict __cond_attr) ;

/* Destroy condition variable */

int pthread_cond_destroy (pthread_cond_t *__cond);

上面两个函数分别由于条件变量的初始化和销毁。

和互斥量的初始化一样,如果条件变量是静态分配的,可以通过常量进行初始化,如下:

pthread_cond_t mlock = PTHREAD_COND_INITIALIZER;

也可以通过pthread_cond_init()进行初始化,对于动态分配的条件变量由于不能直接赋值进行初始化,就只能采用这种方式进行初始化。那么当不在需要使用条件变量时,需要调用pthread_cond_destroy()销毁该条件所占用的资源。

2、条件变量的属性设置

/* 初始化条件变量属性对象 */

int pthread_condattr_init (pthread_condattr_t *__attr);

/* 销毁条件变量属性对象 */

int pthread_condattr_destroy (pthread_condattr_t *__attr);

/* 获取条件变量属性对象在进程间共享与否的标识 */

int pthread_condattr_getpshared (__const pthread_condattr_t * __restrict __attr,

int *__restrict __pshared);

/* 设置条件变量属性对象,标识在进程间共享与否 */

int pthread_condattr_setpshared (pthread_condattr_t *__attr, int __pshared) ;

这个属性的设置和互斥量属性设置是一样的,具体使用可以参考互斥量的用法:互斥量的属性设置。

3、条件变量的使用

/* 等待条件变为真 */

int pthread_cond_wait (pthread_cond_t *__restrict __cond,

pthread_mutex_t *__restrict __mutex);

/* 限时等待条件为真 */

int pthread_cond_timedwait (pthread_cond_t *__restrict __cond,

pthread_mutex_t *__restrict __mutex,

__const struct timespec *__restrict __abstime);

/* 唤醒一个等待条件的线程. */

int pthread_cond_signal (pthread_cond_t *__cond);

/* 唤醒等待该条件的所有线程 */

int pthread_cond_broadcast (pthread_cond_t *__cond);

(1)pthread_cond_wait()函数用于等待条件被触发。该函数传入两个参数,一个条件变量一个互斥量,函数将条件变量和互斥量进行关联,互斥量对该条件进行保护,传入的互斥量必须是已经锁住的。调用pthread_cond_wait()函数后,会原子的执行以下两个动作:

1)将调用线程放到等待条件的线程列表上,即进入睡眠;

2)对互斥量进行解锁;

由于这两个操作时原子操作,这样就关闭了条件检查和线程进入睡眠等待条件改变这两个操作之间的时间通道,这样就不会错过任何条件的变化。

当pthread_cond_wait()返回后,互斥量会再次被锁住。

(2)pthread_cond_timedwait()函数和pthread_cond_wait()的工作方式相似,只是多了一个等待时间。等待时间的结构为struct

timespec,

/* 等待条件变为真 */

int pthread_cond_wait (pthread_cond_t *__restrict __cond,

pthread_mutex_t *__restrict __mutex);

/* 限时等待条件为真 */

int pthread_cond_timedwait (pthread_cond_t *__restrict __cond,

pthread_mutex_t *__restrict __mutex,

__const struct timespec *__restrict __abstime);

/* 唤醒一个等待条件的线程. */

int pthread_cond_signal (pthread_cond_t *__cond);

/* 唤醒等待该条件的所有线程 */

int pthread_cond_broadcast (pthread_cond_t *__cond);

函数要求传入的时间值是一个绝对值,不是相对值,例如,想要等待3分钟,必须先获得当前时间,然后加上3分钟。

要想获得当前系统时间的timespec值,没有直接可调用的函数,需要通过调用gettimeofday函数获取timeval结构,然后转换成timespec结构,转换公式就是:

/* 等待条件变为真 */

int pthread_cond_wait (pthread_cond_t *__restrict __cond,

pthread_mutex_t *__restrict __mutex);

/* 限时等待条件为真 */

int pthread_cond_timedwait (pthread_cond_t *__restrict __cond,

pthread_mutex_t *__restrict __mutex,

__const struct timespec *__restrict __abstime);

/* 唤醒一个等待条件的线程. */

int pthread_cond_signal (pthread_cond_t *__cond);

/* 唤醒等待该条件的所有线程 */

int pthread_cond_broadcast (pthread_cond_t *__cond);

所以要等待3分钟,timespec时间结构的获得应该如下所示:

struct timeval now;

struct timespec until;

gettimeofday(&now);//获得系统当前时间

//把时间从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()成功返回时,线程需要重新计算条件,因为其他线程可能在运行过程中已经改变条件。

(3)pthread_cond_signal() & pthread_cond_broadcast()

这两个函数都是用于向等待条件的线程发送唤醒信号,pthread_cond_signal()函数只会唤醒等待该条件的某个线程,pthread_cond_broadcast()会广播条件状态的改变,以唤醒等待该条件的所有线程。例如多个线程只读共享资源,这是可以将它们都唤醒。

这里要注意的是:一定要在改变条件状态后,再给线程发送信号。

考虑条件变量信号单播发送和广播发送的一种候选方式是坚持使用广播发送。只有在等待者代码编写确切,只有一个等待者需要唤醒,且唤醒哪个线程无所谓,那么此时为这种情况使用单播,所以其他情况下都必须使用广播发送。

下面是一个测试代码,模拟同步问题中经典的生产者消费者问题。

#include

#include

#include

#include

#include

using namespace std;

//把共享数据和它们的同步变量集合到一个结构中,这往往是一个较好的编程技巧。

struct{

pthread_mutex_t mutex;

pthread_cond_t cond;

queue product;

}sharedData = {PTHREAD_MUTEX_INITIALIZER, PTHREAD_COND_INITIALIZER};

void * produce(void *ptr)

{

for (int i = 0; i < 10; ++i)

{

pthread_mutex_lock(&sharedData.mutex);

sharedData.product.push(i);

pthread_mutex_unlock(&sharedData.mutex);

if (sharedData.product.size() == 1)

pthread_cond_signal(&sharedData.cond);

//sleep(1);

}

}

void * consume(void *ptr)

{

for (int i = 0; i < 10;)

{

pthread_mutex_lock(&sharedData.mutex);

while(sharedData.product.empty())

pthread_cond_wait(&sharedData.cond, &sharedData.mutex);

++i;

cout<

sharedData.product.pop();

pthread_mutex_unlock(&sharedData.mutex);

//sleep(1);

}

}

int main()

{

pthread_t tid1, tid2;

pthread_create(&tid1, NULL, consume, NULL);

pthread_create(&tid2, NULL, produce, NULL);

void *retVal;

pthread_join(tid1, &retVal);

pthread_join(tid2, &retVal);

return 0;

}

程序的运行结果如下所示:

consume:0

consume:1

consume:2

consume:3

consume:4

consume:5

consume:6

consume:7

consume:8

consume:9

linux 条件变量函数,Linux线程同步之条件变量相关推荐

  1. Linux——线程同步(条件变量、POSIX信号量)和线程池

    一.线程同步 (一).概念 线程同步是一种多线程关系,指的是线程之间按照特定顺序访问临界资源,进而能够避免线程饥饿问题. 所谓线程饥饿指的是某个线程长期"霸占"临界资源,导致其他线 ...

  2. java线程同步——竞争条件的荔枝+锁对象

    [0]README 0.1) 本文描述转自 core java volume 1, 源代码为原创,旨在理解 java线程同步--竞争条件的荔枝+锁对象 的相关知识: 0.2) for full sou ...

  3. Linux系统编程38:多线程之什么是线程同步以及条件变量函数

    文章目录 (1):什么是线程的同步 (2):实现线程同步-条件变量函数 (1):什么是线程的同步 假如有一片临界资源,线程A和B都会修改它,为了保护资源所以要加锁,此时它们之间是互斥的关系.在我们的代 ...

  4. Linux线程同步之条件变量

    与互斥锁不同,条件变量是用来等待而不是用来上锁的.条件变量用来自动阻塞一个线程,直到某特殊情况发生为止.通常条件变量和互斥锁同时使用. 条件变量使我们可以睡眠等待某种条件出现.条件变量是利用线程间共享 ...

  5. [转]Linux线程同步之条件变量

    与互斥锁不同,条件变量是用来等待而不是用来上锁的.条件变量用来自动阻塞一个线程,直到某特殊情况发生为止.通常条件变量和互斥锁同时使用. 条件变量使我们可以睡眠等待某种条件出现.条件变量是利用线程间共享 ...

  6. linux线程同步(2)-条件变量

    一.概述                                                    上一篇,介绍了互斥量.条件变量与互斥量不同,互斥量是防止多线程同时访问共享的互斥变量来保 ...

  7. Linux系统编程----16(线程同步,互斥量 mutex,互斥锁的相关函数,死锁,读写锁)

    同步概念 所谓同步,即同时起步,协调一致.不同的对象,对"同步"的理解方式略有不同.如,设备同步,是指在两 个设备之间规定一个共同的时间参考:数据库同步,是指让两个或多个数据库内容 ...

  8. UNIX环境高级编程——线程同步之条件变量以及属性

    条件变量变量也是出自POSIX线程标准,另一种线程同步机制.主要用来等待某个条件的发生.可以用来同步同一进程中的各个线程.当然如果一个条件变量存放在多个进程共享的某个内存区中,那么还可以通过条件变量来 ...

  9. 线程同步之条件变量:pthread_cond_signal和pthread_cond_wait

    在多线程编程下,常常出现A线程要等待B线程条件完成后再继续进行,这里等待方式有两种: 1.使用锁+轮询 使用这种方法可以很简单的实现,但是会有一定的性能消耗,其还有一个点要好好把握,就是一次轮询没有结 ...

最新文章

  1. [scrum]2011/9/22-----第二天
  2. EOS 更新合约内部转账方式变化
  3. 应用按home键无最近应用
  4. Onew——全球领先的区块链数字资产服务商
  5. js如何判断当前文本的输入状态——中文输入法的那些坑
  6. 高斯白噪声下基于EM的多径时延估计
  7. 科研福利!国内TOP3的超算中心,免费领2000核时计算资源
  8. 原神服务器维护后抽奖池会更新吗,原神:更新维护一小时,补偿60原石,玩家祈求多维护几天!...
  9. python编写一个弹球游戏_Python实战案例:用Python写一个弹球游戏,就是这么强
  10. 题外话:我想立刻辞职,然后闭关学习编程语言,我给自己3个月时间学习C语言!这样行的通吗...
  11. mac下载站,这个可以收藏看看
  12. Python使用matplotlib可视化模拟商场促销价格关系折线图
  13. 三星s9刷android原生6,【极光ROM】-【三星S9/S9+ G9600/G9650-845】-【V22.0 Android-Q-TF6】...
  14. 视频教程-新版全面系统完整的人工智能教程-机器学习
  15. 3d打印路径规划 matlab,基于FDM技术的3D打印路径规划技术研究
  16. TQuery.RecordCount有时不灵呀
  17. ios和android下数字没有垂直居中,手机端设置小号字体的上下居中问题
  18. Java——迷你图书管理器(JDBC+MySQL+Apache DBUtils)
  19. TPC-H和TPC-DS
  20. 20年嵌入式工程师经验分享:从0开发一款嵌入式产品-道合顺大数据Infinigo

热门文章

  1. 虚拟化宿主服务器网络设置,kvm虚拟化安装配置手册
  2. golang select default continue_Go并发(四):select篇
  3. .mvn 需要放git上吗_下巴反复长痘,饮食上需要忌口吗?
  4. python经济学函数_有没有python计量经济学的教程?
  5. Opencv多通道分离函数split()和多通道合并函数merge的使用
  6. Android AIDL使用介绍(3) 浅说AIDL背后的Binder
  7. BZOJ3862Little Devil I——树链剖分+线段树
  8. ES6之let和const
  9. React Native 模仿网易云音乐手机客户端,兼容安卓和IOS两个平台
  10. Debian 项目不再提供 CD 格式的 ISO 镜像