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. ...
随机推荐
- Summernote – 基于 Bootstrap 的文本编辑器
Summernote 是一个简单,灵活,所见即所得(WYSIWYG)的编辑器,基于 jQuery 和 Bootstrap 构建.Summernote 所有主要的操作都支持快捷键,有一个功能强大的 AP ...
- Materialize - 响应式 Material Design 框架
由谷歌创建和设计的 Material Design(材料设计)是一种设计语言,结合成功的设计的经典原则以及创新科技.谷歌的目标是开发一个设计系统,让所有的产品在任何平台上拥有统一的用户体验. Mate ...
- 简直要逆天!超炫的 HTML5 粒子效果进度条
我喜欢粒子效果作品,特别是那些能够应用于实际的,例如这个由 Jack Rugile 基于 HTML5 Cavnas 编写的进度条效果.看着这么炫的 Loading 效果,即使让我多等一会也无妨:)你呢 ...
- Python开发GIS的应用组件包
Library name Description Reason to install NumPy This adds support for large multidimensional arra ...
- tomcat下运行多个项目
1. tomact下修改端口解决端口冲突 http://jingyan.baidu.com/article/9f63fb91d0f1b8c8400f0e1d.html 打开 servers下面的ser ...
- VMware Data Recovery备份恢复vmware虚拟机
VMware Data Recovery 是VMware虚拟机备份工具,可创建虚拟机备份,同时不会中断虚拟机的使用或虚拟机提供的数据和服务.Data Recovery 管理现有备份,并在这些备份过时后 ...
- JavaScript学习01 语言简介、基本使用和变量声明
JavaScript语言简介.基本使用和变量声明 JavaScript是网景(Netscape)公司开发的一种基于客户端浏览器.面向对象.事件驱动式的网页脚本语言. JavaScript的前身叫Liv ...
- 停止运行ExecutorService中的线程
while(true){ try { sleep(1000); } catch (InterruptedException e) { // TODO Auto-generated catch bloc ...
- NSPredicate
NSPredicate 1. 正则表达式使用单个字符串来描述.匹配一系列符合某个句法规则的字符串.通常被用来检索.替换那些符合某个模式的文本. 2. iOS中正则使用 有三种(NSPredicate, ...
- iOS开发之Runtime使用
runtime简介 RunTime简称运行时.OC就是运行时机制,也就是在运行时候的一些机制,其中最主要的是消息机制. 对于C语言,函数的调用在编译的时候会决定调用哪个函数. 对于OC的函数,属于动态 ...