Linux操作系统下的多线程编程详细解析----条件变量
条件变量通过允许线程阻塞和等待另一个线程发送信号的方法,弥补了互斥锁(Mutex)的不足.
1.初始化条件变量pthread_cond_init
#include <pthread.h>
int pthread_cond_init(pthread_cond_t *cv , const pthread_condattr_t *cattr);
返回值:函数成功返回0;任何其他返回值都表示错误
初始化一个条件变量。当参数cattr为空指针时,函数创建的是一个缺省的条件变量。否则条件变量的属性将由cattr中的属性值来决定。调用 pthread_cond_init函数时,参数cattr为空指针等价于cattr中的属性为缺省属性,只是前者不需要cattr所占用的内存开销。这个函数返回时,条件变量被存放在参数cv指向的内存中。
可以用宏PTHREAD_COND_INITIALIZER来初始化静态定义的条件变量,使其具有缺省属性。这和用pthread_cond_init函数动态分配的效果是一样的。初始化时不进行错误检查。如:
pthread_cond_t cv = PTHREAD_COND_INITIALIZER;
不能由多个线程同时初始化一个条件变量。当需要重新初始化或释放一个条件变量时,应用程序必须保证这个条件变量未被使用。
2.阻塞在条件变量上pthread_cond_wait
#include <pthread.h>
int pthread_cond_wait(pthread_cond_t *cv,
pthread_mutex_t *mutex);
返回值:函数成功返回0;任何其他返回值都表示错误
函数将解锁mutex参数指向的互斥锁,并使当前线程阻塞在cv参数指向的条件变量上。
被阻塞的线程可以被pthread_cond_signal函数,pthread_cond_broadcast函数唤醒,也可能在被信号中断后被唤醒。
pthread_cond_wait函数的返回并不意味着条件的值一定发生了变化,必须重新检查条件的值。
pthread_cond_wait函数返回时,相应的互斥锁将被当前线程锁定,即使是函数出错返回。
一般一个条件表达式都是在一个互斥锁的保护下被检查。当条件表达式未被满足时,线程将仍然阻塞在这个条件变量上。当另一个线程改变了条件的值并向条件变量发出信号时,等待在这个条件变量上的一个线程或所有线程被唤醒,接着都试图再次占有相应的互斥锁。
阻塞在条件变量上的线程被唤醒以后,直到pthread_cond_wait()函数返回之前条件的值都有可能发生变化。所以函数返回以后,在锁定相应的互斥锁之前,必须重新测试条件值。最好的测试方法是循环调用pthread_cond_wait函数,并把满足条件的表达式置为循环的终止条件。如:
pthread_mutex_lock();
while (condition_is_false)
pthread_cond_wait();
pthread_mutex_unlock();
阻塞在同一个条件变量上的不同线程被释放的次序是不一定的。
注意:pthread_cond_wait()函数是退出点,如果在调用这个函数时,已有一个挂起的退出请求,且线程允许退出,这个线程将被终止并开始执行善后处理函数,而这时和条件变量相关的互斥锁仍将处在锁定状态。
3.解除在条件变量上的阻塞pthread_cond_signal
#include <pthread.h>
int pthread_cond_signal(pthread_cond_t *cv);
返回值:函数成功返回0;任何其他返回值都表示错误
函数被用来释放被阻塞在指定条件变量上的一个线程。
必须在互斥锁的保护下使用相应的条件变量。否则对条件变量的解锁有可能发生在锁定条件变量之前,从而造成死锁。
唤醒阻塞在条件变量上的所有线程的顺序由调度策略决定,如果线程的调度策略是SCHED_OTHER类型的,系统将根据线程的优先级唤醒线程。
如果没有线程被阻塞在条件变量上,那么调用pthread_cond_signal()将没有作用。
4.阻塞直到指定时间pthread_cond_timedwait
#include <pthread.h>
#include <time.h>
int pthread_cond_timedwait(pthread_cond_t *cv,
pthread_mutex_t *mp, const structtimespec * abstime);
返回值:函数成功返回0;任何其他返回值都表示错误
函数到了一定的时间,即使条件未发生也会解除阻塞。这个时间由参数abstime指定。函数返回时,相应的互斥锁往往是锁定的,即使是函数出错返回。
注意:pthread_cond_timedwait函数也是退出点。
超时时间参数是指一天中的某个时刻。使用举例:
pthread_timestruc_t to;
to.tv_sec = time(NULL) + TIMEOUT;
to.tv_nsec = 0;
超时返回的错误码是ETIMEDOUT。
5.释放阻塞的所有线程pthread_cond_broadcast
#include <pthread.h>
int pthread_cond_broadcast(pthread_cond_t *cv);
返回值:函数成功返回0;任何其他返回值都表示错误
函数唤醒所有被pthread_cond_wait函数阻塞在某个条件变量上的线程,参数cv被用来指定这个条件变量。当没有线程阻塞在这个条件变量上时,pthread_cond_broadcast函数无效。
由于pthread_cond_broadcast函数唤醒所有阻塞在某个条件变量上的线程,这些线程被唤醒后将再次竞争相应的互斥锁,所以必须小心使用pthread_cond_broadcast函数。
6.释放条件变量pthread_cond_destroy
#include <pthread.h>
int pthread_cond_destroy(pthread_cond_t *cv);
返回值:函数成功返回0;任何其他返回值都表示错误
释放条件变量。
注意:条件变量占用的空间并未被释放。
7.唤醒丢失问题
在线程未获得相应的互斥锁时调用pthread_cond_signal或pthread_cond_broadcast函数可能会引起唤醒丢失问题。
唤醒丢失往往会在下面的情况下发生:
- 一个线程调用pthread_cond_signal或pthread_cond_broadcast函数;
- 另一个线程正处在测试条件变量和调用pthread_cond_wait函数之间;
- 没有线程正在处在阻塞等待的状态下。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h> int i = 0; pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; void* thread1(void *arg)
{
for (;;)
{
printf("thread1 loop...\n");
pthread_mutex_lock(&lock);
printf("thread1 wait cond...\n");
pthread_cond_wait(&cond, &lock);
printf("thread1 work...%d\n", i);
pthread_mutex_unlock(&lock);
} return (void*)0;
} void* thread2(void *arg)
{
sleep(1); while (++i < 100)
{
printf("thread2 loop...\n"); if (i % 10 == 0)
{
pthread_mutex_lock(&lock);
pthread_cond_signal(&cond);
printf("thread2 signal cond...\n");
pthread_mutex_unlock(&lock);
sleep(1);
}
sleep(1);
} printf("thread2 exit\n");
return (void*)0;
} int main(void)
{
pthread_t ntid1;
pthread_t ntid2; pthread_create(&ntid1, NULL, thread1, NULL);
pthread_create(&ntid2, NULL, thread2, NULL); pthread_join(ntid1, NULL);
pthread_join(ntid2, NULL); pthread_mutex_destroy(&lock);
pthread_cond_destroy(&cond); return EXIT_SUCCESS;
}
运行结果如下(部分):
thread1 loop...
thread1 wait cond...
thread2 loop...
thread2 loop...
thread2 loop...
thread2 loop...
thread2 loop...
thread2 loop...
thread2 loop...
thread2 loop...
thread2 loop...
thread2 loop...
thread2 signal cond...
thread1 work...10
thread1 loop...
thread1 wait cond...
thread2 loop...
thread2 loop...
thread2 loop...
thread2 loop...
thread2 loop...
thread2 loop...
thread2 loop...
thread2 loop...
thread2 loop...
thread2 loop...
thread2 signal cond...
thread1 work...20
thread1 loop...
thread1 wait cond...
thread2 loop...
thread2 loop...
thread2 loop...
thread2 loop...
thread2 loop...
thread2 loop...
thread2 loop...
thread2 loop...
thread2 loop...
thread2 loop...
thread2 signal cond...
thread1 work...30
thread1 loop...
thread1 wait cond...
thread2 loop...
thread2 loop...
thread2 loop...
thread2 loop...
thread2 loop...
thread2 loop...
thread2 loop...
thread2 loop...
thread2 loop...
thread2 loop...
Linux操作系统下的多线程编程详细解析----条件变量的更多相关文章
- Linux多线程编程详细解析----条件变量 pthread_cond_t
Linux操作系统下的多线程编程详细解析----条件变量 1.初始化条件变量pthread_cond_init #include <pthread.h> int pthread_cond_ ...
- ZT Linux系统环境下的Socket编程详细解析
Linux系统环境下的Socket编程详细解析 来自: http://blog.163.com/jiangh_1982/blog/static/121950520082881457775/ 什么是So ...
- linux 操作系统下c语言编程入门
2)Linux程序设计入门--进程介绍 3)Linux程序设计入门--文件操作 4)Linux程序设计入门--时间概念 5)Linux程序设计入门--信号处理 6)Linux程序设计入门--消息管理 ...
- [转] linux操作系统下c语言编程入门--基础知识
点击阅读原文 这篇文章介绍在LINUX下进行C语言编程所需要的基础知识.在这篇文章当中,我们将会学到以下内容: 1. 源程序编译 2. Makefile的编写 3. 程序库 ...
- iOS——多线程编程详细解析
基本定义: 程序:由代码生成的可执行应用.(例如QQ.app) 进程:一个正在运行的程序可以看做是一个进程. (例如:正在运行的QQ 就是一个进程),进程拥有独立运行所需要的全部资源. 线程: 程序中 ...
- 多线程编程之Linux环境下的多线程(三)
前面两篇文章都讲述了Linux环境下的多线程编程基础知识,也附带了典型实例.本文主要比较一下Linux环境与Windows环境下的多线程编程区别. 看待技术问题要瞄准其本质,不管是WIN32.Linu ...
- 【转】 Linux下的多线程编程
作者:gnuhpc 出处:http://www.cnblogs.com/gnuhpc/原文链接:http://www.cnblogs.com/gnuhpc/archive/2012/12/07/280 ...
- Linux下的多线程编程
1 引言 线程(thread)技术早在60年代就被提出,但真正应用多线程到操作系统中去,是在80年代中期,solaris是这方面的佼佼者.传统的 Unix也支持线程的概念,但是在一个进程(proces ...
- 【转】Linux下的多线程编程
1 引言 线程(thread)技术早在60年代就被提出,但真正应用多线程到操作系统中去,是在80年代中期,solaris是这方面的佼佼者.传统的 Unix也支持线程的概念,但是在一个进程(proces ...
随机推荐
- 绘制三角形(sass)
绘制三角形 /// draw triangle/// @param {type} $type [''] - triangleUp triangleDown triangleLeft triangleR ...
- mysql中去除重复字段-distinct
1.注意事项 使用distinct命令时需要放在查询条件的开头,否则会报错.如果需要查询的项目很多但只针对某一个字段使用distinct的,则可以利用内容拼接的方式来实现. --基本查询 SELECT ...
- 如何学好C++语言
前段时间写了一篇如何学好C语言,就有人回复问我如何学好C++,所以,我把我个人的一些学习经验写在这里,希望对大家有用.首先,因为如何学好C语言中谈到了算法和系统,所以这里就只谈C++语言. C++是最 ...
- 三十七 Python分布式爬虫打造搜索引擎Scrapy精讲—将bloomfilter(布隆过滤器)集成到scrapy-redis中
Python分布式爬虫打造搜索引擎Scrapy精讲—将bloomfilter(布隆过滤器)集成到scrapy-redis中,判断URL是否重复 布隆过滤器(Bloom Filter)详解 基本概念 如 ...
- jenkins集成maven实现自动化接口测试
当时领导让研究这个,就总结了一个文档,现在记录在这里,给自己留个备份. 1.安装jenkins 地址http://updates.jenkins-ci.org/download/war/ 安装mave ...
- swagger 文件上传
单个文件上传的写法: @RequestParam MultipartFile pictures 多个文件上传的写法: @RequestParam String token,@RequestPart(& ...
- BZOJ3528: [Zjoi2014]星系调查
唉,看到这题直接想起自己的Day1,还是挺难受的,挺傻一题考试的时候怎么就没弄出来呢…… 这两天CP让我给他写个题解,弄了不是很久就把这个题给弄出来了,真不知道考试的时候在干嘛. 明天就出发去北京了, ...
- 014——VUE中v-if语法在网站注册中的实际应用
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...
- OLED取模笔记
- maven pox.xml文件报错解决办法 亲测可以
问题1 由于maven下载依赖包失败导致一些文件没完全下载下来,形成了lastUpdated结尾的文件存放在本地仓库中(我是默认地址:C:\Users\Administrator\.m2\reposi ...