linux c编程:互斥锁条件变量
条件变量:等待与信号发送
使用互斥锁虽然可以解决一些资源竞争的问题,但互斥锁只有两种状态(加锁和解锁),这限制了互斥锁的用途。
条件变量(条件锁)也可以解决线程同步和共享资源访问的问题,条件变量是对互斥锁的补充,它允许一个线程阻塞并等待另一个线程发送的信号,当收到信号时,阻塞的线程被唤醒并试图锁定与之相关的互斥锁。
条件变量初始化
条件变量和互斥锁一样,都有静态动态两种创建方式,静态方式使用PTHREAD_COND_INITIALIZER常量,如下:
pthread_cond_t
cond = PTHREAD_COND_INITIALIZER
动态方式调用函数int
pthread_cond_init,API定义如下:
int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr);
条件变量的属性由参数attr指定,如果参数attr为NULL,那么就使用默认的属性设置。尽管POSIX标准中为条件变量定义了属性,但在LinuxThreads中没有实现,因此cond_attr值通常为NULL,且被忽略。多线程不能同时初始化一个条件变量,因为这是原子操作。如果函数调用成功,则返回0,并将新创建的条件变量的ID放在参数cond中。
解除条件变量
int pthread_cond_destroy(pthread_cond_t *cond);
调用destroy函数解除条件变量并不会释放存储条件变量的内存空间。
条件变量阻塞(等待)
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 *abtime);
等待有两种方式:条件等待pthread_cond_wait()和计时等待pthread_cond_timedwait(),其中计时等待方式如果在给定时刻前条件没有满足,则返回ETIMEDOUT,结束等待,其中abstime以与系统调用time相同意义的绝对时间形式出现,0表示格林尼治时间1970年1月1日0时0分0秒。
无论哪种等待方式,都必须和一个互斥锁配合,以防止多个线程同时请求pthread_cond_wait()或pthread_cond_timedwait()(下同)的竞争条件(Race
Condition)。mutex互斥锁必须是普通锁(PTHREAD_MUTEX_TIMED_NP)或者自适应锁(PTHREAD_MUTEX_ADAPTIVE_NP),且在调用pthread_cond_wait()前必须由本线程加锁(pthread_mutex_lock()),而在更新条件等待队列以前,mutex保持锁定状态,并在线程挂起进入等待前解锁。在条件满足从而离开pthread_cond_wait()之前,mutex将被重新加锁,以与进入pthread_cond_wait()前的加锁动作对应。阻塞时处于解锁状态。
激活
int pthread_cond_signal(pthread_cond_t *cond);
int pthread_cond_broadcast(pthread_cond_t *cond);
pthread_cond_signal函数的作用是发送一个信号给另外一个正在处于阻塞等待状态的线程,使其脱离阻塞状态,继续执行,如果没有线程处在阻塞等待状态,pthread_cond_signal也会成功返回。
共享变量的状态改变必须遵守lock/unlock的规则:需要在同一互斥锁的保护下使用pthread_cond_signal(即pthread_cond_wait必须放在pthread_mutex_lock和pthread_mutex_unlock之间)否则条件变量可以在对关联条件变量的测试和pthread_cond_wait带来的阻塞之间获得信号,这将导致无限期的等待(死锁)。因为他要根据共享变量的状态来决定是否要等待,所以为了避免死锁,必须要在lock/unlock队中。
共享变量的状态改变必须遵守lock/unlock的规则:pthread_cond_signal即可以放在pthread_mutex_lock和pthread_mutex_unlock之间,也可以放在pthread_mutex_lock和pthread_mutex_unlock之后,但是各有优缺点。
若为前者,在某些线程的实现中,会造成等待线程从内核中唤醒(由于cond_signal)然后又回到内核空间(因为cond_wait返回后会有原子加锁的行为),所以一来一回会有性能的问题(上下文切换)。详细来说就是,当一个等待线程被唤醒的时候,它必须首先加锁互斥量(参见pthread_cond_wait()执行步骤)。如果线程被唤醒而此时通知线程任然锁住互斥量,则被唤醒线程会立刻阻塞在互斥量上,等待通知线程解锁该互斥量,引起线程的上下文切换。当通知线程解锁后,被唤醒线程继续获得锁,再一次的引起上下文切换。这样导致被唤醒线程不能顺利加锁,延长了加锁时间,加重了系统不必要的负担。但是在LinuxThreads或者NPTL里面,就不会有这个问题,因为在Linux线程中,有两个队列,分别是cond_wait队列和mutex_lock队列,cond_signal只是让线程从cond_wait队列移到mutex_lock队列,而不用返回到用户空间,不会有性能的损耗,因此Linux推荐这种形式。
而后者不会出现之前说的那个潜在的性能损耗,因为在signal之前就已经释放锁了。但如果unlock和signal之前,有个低优先级的线程正在mutex上等待的话,那么这个低优先级的线程就会抢占高优先级的线程(cond_wait的线程)。而且,假设而这在上面的放中间的模式下是不会出现的。
而对于pthread_cond_broadcast函数,它使所有由参数cond指向的条件变量阻塞的线程退出阻塞状态,如果没有阻塞线程,则函数无效。
实例代码如下:
void *produce_cond(void *arg)
{
for(;;)
{
pthread_mutex_lock(&put.mutex);
if(put.nput >= nitems)
{
pthread_mutex_unlock(&put.mutex);
return NULL;
}
buff[put.nput]=put.nval;
put.nput++;
put.nval++;
pthread_mutex_unlock(&put.mutex);
pthread_mutex_lock(&nready.mutex);
if(nready.nready == 0)
printf("produce_cond nready==0\n");
pthread_cond_signal(&nready.cond);
nready.nready++;
pthread_mutex_unlock(&nready.mutex);
*((int *)arg)+=1;
}
}void *consume_cond(void *arg)
{
int i;
for(i=0;i<3;i++)
{
pthread_mutex_lock(&nready.mutex);
printf("consume_cond nready =%d\n",&nready);
while(nready.nready == 0)
pthread_cond_wait(&nready.cond,&nready.mutex);
nready.nready--;
pthread_mutex_unlock(&nready.mutex);
printf("consume_cond\n");
if(buff[i]!=i)
{
printf("buff[%d]=%d\n",i,buff[i]);
}
}
}
在produce_cond中给用来统计准备好由消费者处理的条目数的计数器nready.nready加一。在加1之前,如果该计数器的值为0,就调用pthread_cond_signal唤醒可能正在等待其值变为非零的任意消费者线程。该计数器是在生产者和消费者之间共享的。因此只有锁住与之关联的互斥所nready.mutex时才能访问它。
consume_cond中消费者只是等待计数器nready.nready变为非零,既然该计数器是在所有生产者和消费者之间共享的。那么只有锁住与之关联的互斥锁时才能测试它的值。如果在锁住该互斥锁期间该计数器的值为0,我们就调用pthread_cond_wait进入睡眠,该函数原子地执行以下两个动作:
1给互斥锁nread.mutex解锁
2把调用线程投入睡眠,直到另外某个线程就本条件变量调用pthread_cond_signal.
pthread_cond_wait在返回前重新给互斥锁nready.mutex上锁。因此当它返回并且我们发现计数器nready.nready不为0时,我们就该把计数器减一,然后给该互斥锁解锁
linux c编程:互斥锁条件变量的更多相关文章
- Linux多线程编程详细解析----条件变量 pthread_cond_t
Linux操作系统下的多线程编程详细解析----条件变量 1.初始化条件变量pthread_cond_init #include <pthread.h> int pthread_cond_ ...
- Linux系统编程 —互斥量mutex
互斥量mutex 前文提到,系统中如果存在资源共享,线程间存在竞争,并且没有合理的同步机制的话,会出现数据混乱的现象.为了实现同步机制,Linux中提供了多种方式,其中一种方式为互斥锁mutex(也称 ...
- Linux Shell编程(8)——变量详解
不同与许多其他的编程语言,Bash不以"类型"来区分变量.本质上来说,Bash变量是字符串,但是根据环境的不同,Bash允许变量有整数计算和比较.其中的决定因素是变量的值是不是只含 ...
- Linux Shell编程(6)——变量替换
变量的名字是它的值保存的地方.引用它的值称为变量替换.$让我们仔细地区别变量和变量的值.如果variable1是一个变量的名字,那么$variable1就是引用这个变量的值――即这个变量它包含的数据. ...
- Linux Shell编程(7)——变量赋值
=赋值操作符(它的左右两边不能有空白符) 不要搞混了=和-eq,-eq是比赋值操作更高级的测试.注意:等于号(=)根据环境的不同它可能是赋值操作符也可能是一个测试操作符.例子:简单的变量赋值 #!/b ...
- Linux系统编程—条件变量
条件变量是用来等待线程而不是上锁的,条件变量通常和互斥锁一起使用.条件变量之所以要和互斥锁一起使用,主要是因为互斥锁的一个明显的特点就是它只有两种状态:锁定和非锁定,而条件变量可以通过允许线程阻塞和等 ...
- MFC编程入门之八(对话框:创建对话框类和添加控件变量)
创建好对话框资源后要做的就是生成对话框类了.生成对话框类主要包括新建对话框类.添加控件变量和控件的消息处理函数. 例程Addition是基于对话框的程序,所以程序自动创建了对话框模板IDD_ADDIT ...
- Linux Shell编程变量赋值和引用
我们可以使用任意一种文字编辑器,比如gedit.kedit.emacs.vi等来编写shell脚本,它必须以如下行开始(必须放在文件的第一行): #!/bin/sh ... 注意:最好使用“! ...
- 【转】VS2010/MFC编程入门之八(对话框:创建对话框类和添加控件变量)
原文网址:http://www.jizhuomi.com/software/153.html 前两讲中鸡啄米为大家讲解了如何创建对话框资源.创建好对话框资源后要做的就是生成对话框类了.鸡啄米再声明下, ...
随机推荐
- 微信中调起qq
http://wpa.qq.com/msgrd?uin={$qq}&menu=yes
- 基于Java语言开发jt808、jt809技术文章精华索引
很多技术开发人员喜欢追逐最新的技术,如Node.js, go等语言,这些语言只是解决了某一个方面,如只是擅长异步高并发等等,却在企业管理后台开发方面提供的支持非常不够,造成项目团队技术选项失败,开发后 ...
- 跟着百度学PHP[14]-COOKIE的应用/网站登陆案例完整案例
先在数据库当中创建以下数据: mysql> create table user( -> id int not null auto_increment, ) not null default ...
- (译)Getting Started——1.2.2 Desinging a User Interface(设计用户界面)
用户需要以最简单的方式与应用界面进行交互.应该从用户的角度出发设计页面,使得界面更高效.简捷和直接. storyboard以图形化的方式帮助你设计和实现界面.在设计和实现界面的过程中,你 ...
- visitor设计模式记录
数据类型通过枚举来区分是一种简单实用的做法. 缺点是使用的时候需要通过if .switch 去判断什么类型执行什么分支操作,说是缺点其实也要看具体场景.不过如果if代码多会导致代码很长是肯定的. 复杂 ...
- poj3680 Intervals 区间k覆盖问题 最小费用最大流 建图巧妙
/** 题目:poj3680 Intervals 区间k覆盖问题 最小费用最大流 建图巧妙 链接:http://poj.org/problem?id=3680 题意:给定n个区间,每个区间(ai,bi ...
- centos yum安装及手动编译ettercap
眼下流行的软件包有二种形式 ,一种是以rpm包,deb包为代表的智能安装包.还有一种是以file.tar.gz形式的压缩 一 智能安装 以 mysql为例 yum search mysqld 二 手动 ...
- 同学帮帮 h5 刮刮卡组件:Txbb.Scratch
同学帮帮 h5 刮刮卡组件,简洁.无依赖,支持 globals 和 amd 两种调用方式. 暂时只能用在移动端 使用方法 <div id="J-Scratch">< ...
- 第二百三十一节,Bootstrap 介绍
Bootstrap 介绍 学习要点: 1.Bootstrap 概述 2.Bootstrap 特点 3.Bootstrap 结构 4.创建第一个页面 5.学习的各项准备 本节课我们主要了解一下 Boos ...
- apache的ab命令做压力测试
1. 最基本的关心两个选项 -c -n 例: ./ab -c 100 -n 10000 http://127.0.0.1/index.php -c 100 即:每次并发100个-n 10000 即: ...