linux线程同步(2)-条件变量
一.概述
上一篇,介绍了互斥量。条件变量与互斥量不同,互斥量是防止多线程同时访问共享的互斥变量来保护临界区。条件变量是多线程间可以通过它来告知其他线程某个状态发生了改变,让等待在这个条件变量的线程继续执行。通俗一点来讲:设置一个条件变量让线程1等待在一个临界区的前面,当其他线程给这个变量执行通知操作时,线程1才会被唤醒,继续向下执行。
条件变量总是和互斥量一起使用,互斥量保护着条件变量,防止多个线程对条件变量产生竞争。等会写个小例子,看它们如何一起合作!
二.函数接口
1.初始化条件变量
1.1:宏常量初始化
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
1.2:函数初始化
#include <pthread.h> int pthread_cond_init(pthread_cond_t *restrict cond, const pthread_condattr_t *restrict attr);
跟互斥量类似,cond是条件变量的结构指针,attr是条件变量属性的结构指针。
2.等待和通知条件变量
#include <pthread.h> int pthread_cond_timedwait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex, const struct timespec *restrict abstime); int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex); int pthread_cond_broadcast(pthread_cond_t *cond); int pthread_cond_signal(pthread_cond_t *cond);
等待函数里面,要传入一个互斥量。pthread_cond_timewait()可以指定一个时间来等待,如果规定的时间没有获得通知,就返回ETIMEDOUT错误。而pthread_cond_wait()会一直阻塞。
通知函数,pthread_cond_signal()至少唤醒一个等待的线程,pthread_cond_broadcast()会唤醒在该条件变量上所有线程。
3.销毁条件变量
#include <pthread.h> int pthread_cond_destroy(pthread_cond_t *cond);
三.简单的例子
我们还是用上一篇互斥量的例子。单独使用互斥量时,有些线程要获取某个状态的成立,需要多次进出临界区,对互斥量频繁加锁解锁造成系统资源的浪费。下面结合条件变量来解决这个问题:
/**
* @file pthread_mutex.c
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
/* 定义互斥量 */
pthread_mutex_t mtx;
/* 互斥量属性 */
pthread_mutexattr_t mtx_attr;
/* 全局资源 */
int money;
/* 条件变量 */
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
void err_exit(const char *err_msg)
{
printf("error:%s\n", err_msg);
exit();
}
/* 线程函数 */
void *thread_fun(void *arg)
{
)
{
/* 加锁 */
pthread_mutex_lock(&mtx);
/* 条件变量 */
)
{
printf("子线程坐等money等于0...\n");
pthread_cond_wait(&cond, &mtx);
}
printf("子线程进入临界区查看money\n");
)
{
money += ;
printf("子线程:money = %d\n", money);
}
/* 解锁 */
pthread_mutex_unlock(&mtx);
sleep();
}
return NULL;
}
int main(void)
{
pthread_t tid;
/* 初始化互斥量属性 */
)
err_exit("pthread_mutexattr_init()");
/* 设置互斥量属性 */
)
err_exit("pthread_mutexattr_settype()");
/* 初始化互斥量 */
)
err_exit("pthread_mutex_init()");
/* 创建一个线程 */
)
err_exit("pthread_create()");
money = ;
)
{
/* 加锁 */
pthread_mutex_lock(&mtx);
)
{
money -= ;
printf("主线程:money = %d\n", money);
}
/* 解锁 */
pthread_mutex_unlock(&mtx);
/* 如果money = 1,就通知子线程 */
)
{
printf("通知子线程\n");
pthread_cond_signal(&cond);
}
sleep();
}
;
}
代码跟上一个例子几乎一样,就加了一个条件变量。编译运行:

可以看到第39行的等待条件变量触发后,子线程会一直等待,直到主线程通知它。这样子线程就不会频繁进入临界区,频繁加锁解锁。
四.深入知识
1.等待函数里面要传入一个互斥量,这个互斥量会在这个函数调用时会发生如下变化:函数刚刚被调用时,会把这个互斥量解锁,然后让调用线程阻塞,解锁后其他线程才有机会获得这个锁。当某个线程调用通知函数时,这个函数收到通知后,又把互斥量加锁,然后继续向下操作临界区。可见这个设计是非常合理的!!!
2.条件变量的等待函数用while循环包围,本程序的第36行。原因:如果有多个线程都在等待这个条件变量关联的互斥量,当条件变量收到通知,它下一步就是要锁住这个互斥量,但在这个极小的时间差里面,其他线程抢先获取了这互斥量并进入临界区把某个状态改变了。此时这个条件变量应该继续判断别人刚刚抢先修改的状态,即继续执行while的判断。还有一个原因时防止虚假通知,收到虚假通知后,只要while里面的条件为真,就继续休眠!!!
linux线程同步(2)-条件变量的更多相关文章
- Linux线程同步:条件变量
条件变量通过允许线程阻塞和等待另一个线程发送信号的方法弥补了互斥锁的不足,它常和互斥锁一起使用.使用时,条件变量被用来阻塞一个线程,当条件不满足时,线程往往解开相应的互斥锁并等待条件发生变化.一旦其它 ...
- 线程同步,条件变量pthread_cond_wait
与互斥锁不同,条件变量是用来等待而不是用来上锁的.条件变量用来自动阻塞一个线程,直到某特殊情况发生为止.条件变量使我们可以睡眠等待某种条件出现.条件变量是利用线程间共享的全局变量进行同步的一种机制,主 ...
- 四十二、Linux 线程——线程同步之条件变量之线程状态转换
42.1 线程状态转换 42.1.1 状态转换图 42.1.2 一个线程计算,多个线程获取的案例 #include <stdio.h> #include <stdlib.h> ...
- 四十一、Linux 线程——线程同步之条件变量
41.1 概念 41.1.1 条件变量的介绍 互斥锁的缺点是它只有两种状态:锁定和非锁定 条件变量通过允许线程阻塞和等待另一个线程发送信号的方法弥补了互斥锁的不足 条件变量内部是一个等待队列,放置等待 ...
- linux多线程同步pthread_cond_XXX条件变量的理解
在linux多线程编程中,线程的执行顺序是不可预知的,但是有时候由于某些需求,需要多个线程在启动时按照一定的顺序执行,虽然可以使用一些比较简陋的做法,例如:如果有3个线程 ABC,要求执行顺序是A-- ...
- UNIX环境高级编程——线程同步之条件变量以及属性
条件变量变量也是出自POSIX线程标准,另一种线程同步机制.主要用来等待某个条件的发生.可以用来同步同一进程中的各个线程.当然如果一个条件变量存放在多个进程共享的某个内存区中,那么还可以通过条件变量来 ...
- [b0034] python 归纳 (十九)_线程同步_条件变量
代码: # -*- coding: utf-8 -*- """ 学习线程同步,使用条件变量 逻辑: 生产消费者模型 一个有3个大小的产品库,一个生产者负责生产,一个消费者 ...
- Linux线程同步——条件变量
互斥锁是用来给资源上锁的,而条件变量是用来等待而不是用来上锁的. 条件变量用来自动阻塞一个线程,直到某特殊情况发生为止. 通常条件变量和互斥锁同时使用. 和条件变量使用有关的几个重要函数: int p ...
- Linux 线程同步的三种方法(互斥锁、条件变量、信号量)
互斥锁 #include <cstdio> #include <cstdlib> #include <unistd.h> #include <pthread. ...
随机推荐
- loadrunner录制回放常见问题及解决办法
1.录制错误 1)录制本机 WebTours 或录制本地网站无法打开 当 使 用 Vista 以 后 的 操 作 系 统 时 , 会 出 现 该 问 题 . 这 是 由 于 在 本 地Wi ...
- 设计3D标签
java自带的Label太枯燥了,真是拿不出手啊. 所以,我们要设计3D标签!! 看看下面这张图 原理 看看这图,可以看到哈哈有三种颜色:白色.黑色和灰色 实现的时候并不像PS那样,按几个按钮就O了 ...
- jQuery als.js 跑马灯
ali.js是一款滚动插件,滚动的内容可包含文字和图片.它的API也很强大,包括滚动区域可见个数.每次滚动个数.滚动方向.是否循环滚动.是否自动滚动.滚动间隔时间.滚动动画速度.动画效果.滚动方向以及 ...
- Captain Icon – 350+ 有趣的矢量图标免费下载
Captain Icon 是一套一个惊人的免费图标集,包含350+有趣的矢量图标,可以缩放到任意大小而不会降低质量.图标的类别很丰富,有设计,体育,社会,天气等很多类别.提供 EPS.PSD.PNG. ...
- 国外经典设计:12个漂亮的移动APP网站案例
优秀的移动应用程序网站是设计灵感的重要来源.从美丽的图像,合理的使用空白到排版和颜色的使用,似乎设计师都加倍努力以创造一些美好和独特的设计来推广自己的应用程序. 因此,在这篇文章中,我们已经聚集了13 ...
- IOS 局域网发送信息
基于ios 例子WiTap 1.创建本地的服务并设置监听时间检测是否有设备连接. NSNetService * server = [[NSNetService alloc] initWithDomai ...
- javascript 函数初探 (六)--- 闭包初探#4
循环中的闭包: 让我们来看一下一个会循环三次的操作,她在每次迭代中都会创建一个返回当前序列号的新函数,该函数会被添加到一个数组中,并最终返回: function F(){ var arr = [], ...
- 在Android Stuido中使用Lint
要运行Lint工具,大家首先需要在Android Studio的“Analyze”菜单中选择“Inspect Code…”.当Android Studio完成了对项目的检测之后,它会在窗口底部显示出分 ...
- Android 4.4 KitKat 新特性
New in Android 4.4 KitKat 本文是一个概览,关于KitKat,也即Android4.4的新东西,先是功能型的,之后是设计上的. 很多特性本文并没有提到,很多提到的特性也只是简短 ...
- Android与JS之间跨平台异步调用
为什么突然要搞这个问题呢? 在开发浏览器的时候遇到这个狗血的问题,花了将近1天的时间才想到这个解决方案,Android与JavaScirpt互调. 因为接口是抓取的别人的,所以出现了JS跨域问题, ...