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. ...
随机推荐
- Python读写excel
#-*- coding:utf-8 -*- #__author__ = 'liu-ke' import xlrd from xlutils.copy import copy mybook = xlrd ...
- selenium + python自动化测试环境搭建
selenium的在python平台的搭建: 搭建平台windows 准备工具如下: --------------------------------------------------------- ...
- 硬连接与软连接,inode与links
硬连接和软连接,第一感觉就像是window的快捷方式,实则不然 要说硬连接和软连接,那就必须了解inode和block以及分区了 EXT文件系统在创建分区的时候,就划分了两块区域,inode tabl ...
- 12款最佳的 WordPress 语法高亮插件推荐
语法高亮工具增强了代码的可读性,美化了代码,让程序员更容易维护.语法高亮提供各种方式由以提高可读性和文本语境,尤其是对于其中可以结束跨越多个页面的代码,以及让开发者自己的程序中查找错误.在这篇文章中, ...
- js获取页面中图片的总数
查看效果:http://keleyi.com/keleyi/phtml/image/9.htm 下面是完整代码: <html><body><div id="ke ...
- 常用的css命名规则
头:header 内容:content/container 尾:footer 导航:nav 侧栏:sidebar 栏目:column 页面外围控制整体布局宽度:wrapper 左右中:left rig ...
- iOS UIAlertController
在Xcode的iOS9.0 SDK中,UIAlertView和UIActionSheet都被UIAlertController取代. 在iOS 9中,UIAlertController在功能上是和UI ...
- openlayers方法总结
openlayers中的一些方法:OpenLayers.Layer::initialize:创建层Div,注册事件:destroy:注销:clone:克隆当前层:setName:设置层name:add ...
- IOS圆头像
前言 随着腾讯QQ的普及,现在越来越多的社交类APP在显示好友头像时,都选择用圆形头像,效果如下(不包括黑底): 在ios开发中,大致有以下三种方案来实现圆形头像效果. 方案一:用Quartz2D绘制 ...
- 【代码笔记】iOS-翻书效果的实现
代码: RootViewController.m #import "RootViewController.h" @interface RootViewController () @ ...