1. 背景

多线程中经常需要使用到锁(pthread_mutex_t)来完成多个线程之间的互斥操作。

但是互斥锁有一个明显到缺点: 只有两种状态,锁定和非锁定。

而条件变量则通过允许线程阻塞并等待另一个线程发送唤醒信号的方法弥补了互斥锁的不足,它常和互斥锁一起使用。

2. 条件变量涉及到的主要函数

2.1 pthread_cond_wait 线程阻塞在条件变量

int pthread_cond_wait(pthread_cond_t *cv, pthread_mutex_t *mutex);

函数将解锁mutex参数指向的互斥锁,并使当前线程阻塞在cv参数指向的条件变量上。
被阻塞的线程可以被pthread_cond_signal函数,pthread_cond_broadcast函数唤醒,也可能在被信号中断后被唤醒。
pthread_cond_wait函数返回时,相应的互斥锁将被当前线程锁定,即使是函数出错返回。
pthread_cond_wait函数的返回并不意味着条件的值一定发生了变化,必须重新检查条件的值。
最好的测试方法是循环调用pthread_cond_wait函数,并把满足条件的表达式置为循环的终止条件。
 pthread_mutex_lock();
while (condition_is_false)
pthread_cond_wait();
pthread_mutex_unlock();
阻塞在同一个条件变量上的不同线程被唤醒的次序是不一定的。

2.2 pthread_cond_signal 线程被唤醒

int pthread_cond_signal(pthread_cond_t *cv);
函数被用来释放被阻塞在指定条件变量上的一个线程。
必须在互斥锁的保护下使用相应的条件变量。否则对条件变量的解锁有可能发生在锁定条件变量之前,从而造成死锁。
唤醒阻塞在条件变量上的所有线程的顺序由调度策略决定,如果线程的调度策略是SCHED_OTHER类型的,系统将根据线程的优先级唤醒线程。
如果没有线程被阻塞在条件变量上,那么调用pthread_cond_signal()将没有作用。

更多函数可以看: http://blog.csdn.net/icechenbing/article/details/7662026

3. 实例代码

实现功能: 2个线程对count每次分别加1, 第三个线程等count大于10后一次加100.

3.1 加1线程函数

 void *inc_count(void *idp)
{
int i = ;
int taskid = ;
int *my_id = (int*)idp; for (i=; i<TCOUNT; i++) {
pthread_mutex_lock(&count_mutex);
taskid = count;
count++; /*
唤醒一个阻塞在该条件变量到线程
如果没有线程被阻塞在条件变量上,那么调用pthread_cond_signal()将没有作用
*/
pthread_cond_signal(&count_threshold_cv); printf("inc_count(): thread %d, count = %d, unlocking mutex\n", *my_id, count);
pthread_mutex_unlock(&count_mutex);
sleep();
}
printf("inc_count(): thread %d, Threshold reached.\n", *my_id); pthread_exit(NULL);
}

3.2 count满足条件后, 单次加100函数

 void *watch_count(void *idp)
{
int *my_id = (int*)idp;
printf("Starting watch_count(): thread %d\n", *my_id); pthread_mutex_lock(&count_mutex);
while(count<COUNT_LIMIT) {
sleep();
/*
函数将自动/原子的解锁count_mutex参数指向的互斥锁,并使当前线程阻塞在cv参数指向的条件变量上
被阻塞的线程可以被pthread_cond_signal函数,pthread_cond_broadcast函数唤醒,也可能在被信号中断后被唤醒
pthread_cond_wait函数的返回并不意味着条件的值一定发生了变化,必须重新检查条件的值.
本例子中线程被唤醒后, 仍然在while内会再次判断COUNT_LIMIT是否满足条件的值
pthread_cond_wait函数返回时,相应的互斥锁将被当前线程锁定,即使是函数出错返回
*/
pthread_cond_wait(&count_threshold_cv, &count_mutex);
printf("watch_count(): thread %d Condition signal received.\n", *my_id);
} count += ;
pthread_mutex_unlock(&count_mutex);
pthread_exit(NULL);
}

3.3 整体代码

 #include <pthread.h>
#include <stdio.h>
#include <unistd.h> #define NUM_THREADS 3
#define TCOUNT 10
#define COUNT_LIMIT 10 int count = ;
int thread_ids[] = {,,};
pthread_mutex_t count_mutex;
pthread_cond_t count_threshold_cv; void *inc_count(void *idp)
{
int i = ;
int taskid = ;
int *my_id = (int*)idp; for (i=; i<TCOUNT; i++) {
pthread_mutex_lock(&count_mutex);
taskid = count;
count++; /*
唤醒一个阻塞在该条件变量到线程
如果没有线程被阻塞在条件变量上,那么调用pthread_cond_signal()将没有作用
*/
pthread_cond_signal(&count_threshold_cv); printf("inc_count(): thread %d, count = %d, unlocking mutex\n", *my_id, count);
pthread_mutex_unlock(&count_mutex);
sleep();
}
printf("inc_count(): thread %d, Threshold reached.\n", *my_id); pthread_exit(NULL);
} void *watch_count(void *idp)
{
int *my_id = (int*)idp;
printf("Starting watch_count(): thread %d\n", *my_id); pthread_mutex_lock(&count_mutex);
while(count<COUNT_LIMIT) {
sleep();
/*
函数将自动/原子到解锁mutex参数指向的互斥锁,并使当前线程阻塞在cv参数指向的条件变量上
被阻塞的线程可以被pthread_cond_signal函数,pthread_cond_broadcast函数唤醒,也可能在被信号中断后被唤醒
pthread_cond_wait函数的返回并不意味着条件的值一定发生了变化,必须重新检查条件的值.
本例子中使用类COUNT_LIMIT最为满足条件的值
pthread_cond_wait函数返回时,相应的互斥锁将被当前线程锁定,即使是函数出错返回
*/
pthread_cond_wait(&count_threshold_cv, &count_mutex);
printf("watch_count(): thread %d Condition signal received.\n", *my_id);
} count += ;
pthread_mutex_unlock(&count_mutex);
pthread_exit(NULL);
} int main (int argc, char *argv[])
{
int i, rc;
pthread_t threads[];
pthread_attr_t attr; /* Initialize mutex and condition variable objects */
pthread_mutex_init(&count_mutex, NULL);
pthread_cond_init (&count_threshold_cv, NULL); /* For portability, explicitly create threads in a joinable state */
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
pthread_create(&threads[], &attr, inc_count, (void *)&thread_ids[]);
pthread_create(&threads[], &attr, inc_count, (void *)&thread_ids[]);
pthread_create(&threads[], &attr, watch_count, (void *)&thread_ids[]); /* Wait for all threads to complete */
for (i=; i<NUM_THREADS; i++) {
pthread_join(threads[i], NULL);
}
printf ("Main(): Waited on %d threads. Done.\n", NUM_THREADS); /* Clean up and exit */
pthread_attr_destroy(&attr);
pthread_mutex_destroy(&count_mutex);
pthread_cond_destroy(&count_threshold_cv);
pthread_exit(NULL); return ;
}

linux C++ 多线程使用pthread_cond 条件变量的更多相关文章

  1. linux多线程同步pthread_cond_XXX条件变量的理解

    在linux多线程编程中,线程的执行顺序是不可预知的,但是有时候由于某些需求,需要多个线程在启动时按照一定的顺序执行,虽然可以使用一些比较简陋的做法,例如:如果有3个线程 ABC,要求执行顺序是A-- ...

  2. 详解linux互斥锁 pthread_mutex和条件变量pthread_cond

    [cpp] view plaincopy ============================================================= int pthread_creat ...

  3. Linux多线程编程的条件变量

    在stackoverflow上看到一关于多线程条件变量的问题,题主问道:什么时候会用到条件变量,mutex还不够吗?有个叫slowjelj的人做了很好的回答,我再看这个哥们其他话题的一些回答,感觉水平 ...

  4. Linux 多线程编程—使用条件变量实现循环打印

    编写一个程序,开启3个线程,这3个线程的ID分别为A.B.C,每个线程将自己的ID在屏幕上打印10遍,要求输出结果必须按ABC的顺序显示:如:ABCABC….依次递推. 使用条件变量来实现: #inc ...

  5. 多线程编程中条件变量和的spurious wakeup 虚假唤醒

    1. 概述 条件变量(condition variable)是利用共享的变量进行线程之间同步的一种机制.典型的场景包括生产者-消费者模型,线程池实现等. 对条件变量的使用包括两个动作: 1) 线程等待 ...

  6. linux网络编程之posix条件变量

    今天来学习posix的最后一个相关知识----条件变量,言归正传. 下面用一个图来进一步描述条件变量的作用: 为什么呢? 这实际上可以解决生产者与消费者问题,而且对于缓冲区是无界的是一种比较理解的解决 ...

  7. 练习生产者与消费者-PYTHON多线程中的条件变量同步-Queue

    以前练习过,但好久不用,手生,概念也生了, 重温一下.. URL: http://www.cnblogs.com/holbrook/tag/%E5%A4%9A%E7%BA%BF%E7%A8%8B/ ~ ...

  8. 四十二、Linux 线程——线程同步之条件变量之线程状态转换

    42.1 线程状态转换 42.1.1 状态转换图 42.1.2 一个线程计算,多个线程获取的案例 #include <stdio.h> #include <stdlib.h> ...

  9. 四十一、Linux 线程——线程同步之条件变量

    41.1 概念 41.1.1 条件变量的介绍 互斥锁的缺点是它只有两种状态:锁定和非锁定 条件变量通过允许线程阻塞和等待另一个线程发送信号的方法弥补了互斥锁的不足 条件变量内部是一个等待队列,放置等待 ...

随机推荐

  1. 浅谈2-SAT(待续)

    2-SAT问题,其实是一个逻辑互斥问题.做了两道裸题之后仔细想来,和小时候做过的“有两个女生,如果A是女生,那么B一定不是女生.A和C性别相同,求A.B.C三人的性别.”几乎是一样的. 对于这道题我们 ...

  2. 使用ApiPost测试接口时需要先登录怎么办?利用Cookie模拟登陆!

    ApiPost简介: ApiPost是一个支持团队协作,并可直接生成文档的API调试.管理工具.它支持模拟POST.GET.PUT等常见请求,是后台接口开发者或前端.接口测试人员不可多得的工具 . 下 ...

  3. [USACO08OCT]Watering Hole

    [USACO08OCT]Watering Hole 题目大意: Farmer John 有\(n(n\le300)\)个牧场,他希望灌溉他的所有牧场.牧场编号为\(1\sim n\),要灌溉一个牧场有 ...

  4. makefile 必知必会以及Makefile是怎样炼成的

    Make必知必会原文链接 Makefile 必知必会 Makefile的根本任务是根据规则生成目标文件. 规则 一条规则包含三个:目标文件,目标文件依赖的文件,更新(或生成)目标文件的命令. 规则: ...

  5. Windows 7硬盘安装CentOS 6.4 双系统 (WIN7下硬盘安装Linux(Fedora 16,CentOS 6.2,Ubuntu 12.04))

     WIN7下硬盘安装Linux(Fedora 16,CentOS 6.2,Ubuntu 12.04) 最近在看<鸟哥私房菜:基础学习篇>,觉得很不错,想要用U盘装个windows 7 和 ...

  6. Codeforces Round #394 (Div. 2) D. Dasha and Very Difficult Problem 贪心

    D. Dasha and Very Difficult Problem 题目连接: http://codeforces.com/contest/761/problem/D Description Da ...

  7. @Transactional导致无法动态数据源切换

    公司目前数据源为主从模式:主库可读写,从库只负责读.使用spring-jdbc提供的AbstractRoutingDataSource结合ThreadLocal存储key,实现数据源动态切换. 最近项 ...

  8. Visual studio 2010出现“error LNK1123: 转换到 COFF 期间失败: 文件无效或损坏”解决方式

    本来自己的电脑上装了VS2010,因为开发Cocos2d-x 3.x,所以就在自己的机器上装了一个VS2012. 但是.这不装不要紧,debug一下自己原来的程序,结果出现了"error L ...

  9. android开发之GestureDetector手势识别(调节音量、亮度、快进和后退)

    写UI布局: <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:andro ...

  10. [Office Web Apps]实现在线office文档预览

    摘要 在使用office web apps实现office文档在线预览的时候,需要注意的地方. web api web api作为owa在线预览服务回调的接口,这里面核心代码片段如下: using H ...