前面的一片文章我们已经讲过使用信号量解决生产者消费者问题。那么什么情况下我们须要引入条件变量呢?

这里借用  http://www.cnblogs.com/ngnetboy/p/3521547.html 的解释:

如果有共享的资源sum,与之相关联的mutex 是lock_s.如果每一个线程对sum的操作非常easy的,与sum的状态无关,比方仅仅是sum++.那么仅仅用mutex足够了.程序猿仅仅要确保每一个线程操作前,取得lock,然后sum++,再unlock就可以.每一个线程的代码将像这样:

add()
{
pthread_mutex_lock(lock_s);
sum++;
pthread_mutex_unlock(lock_s);
}

假设操作比較复杂,假设线程t0,t1,t2的操作是sum++,而线程t3则是在sum到达100的时候,打印出一条信息,并对sum清零. 这样的情况下,假设仅仅用mutex, 则t3须要一个循环,每一个循环里先取得lock_s,然后检查sum的状态,假设sum>=100,则打印并清零,然后unlock.假设sum<100,则unlock,并sleep()本线程合适的一段时间。

这个时候,t0,t1,t2的代码不变,t3的代码例如以下:

print()
{
while (1)
{
pthread_mutex_lock(lock_s);
if(sum<100)
{
printf(“sum reach 100!”);
pthread_mutex_unlock(lock_s);
}
else
{
pthread_mutex_unlock(lock_s);
my_thread_sleep(100);
return OK;
}
}
}

这样的办法有两个问题

1) sum在大多数情况下不会到达100,那么对t3的代码来说,大多数情况下,走的是else分支,仅仅是lock和unlock,然后sleep().这浪费了CPU处理时间.

2) 为了节省CPU处理时间,t3会在探測到sum没到达100的时候sleep()一段时间.这样却又带来另外一个问题,亦即t3响应速度下降.可能在sum到达200的时候,t4才会醒过来.

3) 这样,程序猿在设置sleep()时间的时候陷入两难境界,设置得太短了节省不了资源,太长了又减少响应速度.真是难办啊!

这个时候,condition variable,从天而降,解救了焦头烂额的你.

你首先定义一个condition variable.

pthread_cond_t cond_sum_ready=PTHREAD_COND_INITIALIZER;

t0,t1,t2的代码仅仅要后面加两行,像这样:

add()
{
pthread_mutex_lock(lock_s);
sum++;
pthread_mutex_unlock(lock_s);
if(sum>=100)
pthread_cond_signal(&cond_sum_ready);
}
而t3的代码则是
print
{
pthread_mutex_lock(lock_s);
while(sum<100)
pthread_cond_wait(&cond_sum_ready, &lock_s);
printf(“sum is over 100!”);
sum=0;
pthread_mutex_unlock(lock_s);
return OK;
}

注意两点:

1) 在thread_cond_wait()之前,必须先lock相关联的mutex, 由于假如目标条件未满足,pthread_cond_wait()实际上会unlock该mutex, 然后block,在目标条件满足后再又一次lock该mutex, 然后返回.

2) 为什么是while(sum<100),而不是if(sum<100) ?这是由于在pthread_cond_signal()和pthread_cond_wait()返回之间,有时间差,如果在这个时间差内,还有另外一个线程t4又把sum降低到100下面了,那么t3在pthread_cond_wait()返回之后,显然应该再检查一遍sum的大小.这就是用 while的用意

线程间的同步技术。主要以相互排斥锁和条件变量为主,条件变量和相互排斥所的配合使用能够非常好的处理对于条件等待的线程间的同步问题

Posix条件变量经常使用API:

int pthread_cond_init(pthread_cond_t *cond, pthread_condattr_t *cond_attr);
int pthread_cond_destroy(pthread_cond_t *cond); 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 *abstime); int pthread_cond_signal(pthread_cond_t *cond);
int pthread_cond_broadcast(pthread_cond_t *cond);

通常条件变量须要和相互排斥锁同一时候使用, 利用相互排斥量保护条件变量;条件的检測是在相互排斥锁的保护下进行的。

假设一个条件为假,一个线程自己主动堵塞,并释放等待状态改变的相互排斥锁。假设还有一个线程改变了条件,它就发送信号给关联的条件变量, 并唤醒一个或多个等待在该条件变量上的线程,这些线程将又一次获得相互排斥锁,又一次评价条件。假设将条件变量放到共享内存中, 而两进程可共享读写这段内存,则条件变量能够被用来实现两进程间的线程同步。

条件变量的使用规范:

(一)、等待条件代码
pthread_mutex_lock(&mutex);
while (条件为假)
pthread_cond_wait(cond, mutex);
改动条件
pthread_mutex_unlock(&mutex); (二)、给条件发送通知代码
pthread_mutex_lock(&mutex);
设置条件为真
pthread_cond_signal(cond);
pthread_mutex_unlock(&mutex);

注意是while而不是if,原因是在信号的中断后还能正常执行。

解决生产者消费者问题(无界缓冲区):

#include <unistd.h>
#include <sys/types.h>
#include <pthread.h>
#include <semaphore.h> #include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h> #define ERR_EXIT(m) \
do \
{ \
perror(m); \
exit(EXIT_FAILURE); \
} while(0) #define CONSUMERS_COUNT 2
#define PRODUCERS_COUNT 1 pthread_mutex_t g_mutex;
pthread_cond_t g_cond; pthread_t g_thread[CONSUMERS_COUNT + PRODUCERS_COUNT]; int nready = 0; void *consume(void *arg)
{
int num = (int)arg;
while (1)
{
pthread_mutex_lock(&g_mutex);
while (nready == 0)
{
printf("%d begin wait a condtion ...\n", num);
pthread_cond_wait(&g_cond, &g_mutex);
} printf("%d end wait a condtion ...\n", num);
printf("%d begin consume product ...\n", num);
--nready;
printf("%d end consume product ...\n", num);
pthread_mutex_unlock(&g_mutex);
sleep(1);
}
return NULL;
} void *produce(void *arg)
{
int num = (int)arg;
while (1)
{
pthread_mutex_lock(&g_mutex);
printf("%d begin produce product ...\n", num);
++nready;
printf("%d end produce product ...\n", num);
pthread_cond_signal(&g_cond);
printf("%d signal ...\n", num);
pthread_mutex_unlock(&g_mutex);
sleep(1);
}
return NULL;
} int main(void)
{
int i; pthread_mutex_init(&g_mutex, NULL);
pthread_cond_init(&g_cond, NULL); for (i = 0; i < CONSUMERS_COUNT; i++)
pthread_create(&g_thread[i], NULL, consume, (void *)i); sleep(1); for (i = 0; i < PRODUCERS_COUNT; i++)
pthread_create(&g_thread[CONSUMERS_COUNT + i], NULL, produce, (void *)i); for (i = 0; i < CONSUMERS_COUNT + PRODUCERS_COUNT; i++)
pthread_join(g_thread[i], NULL); pthread_mutex_destroy(&g_mutex);
pthread_cond_destroy(&g_cond); return 0;
}

Linux多线程实践(六)使用Posix条件变量解决生产者消费者问题的更多相关文章

  1. Linux多线程实践(8) --Posix条件变量解决生产者消费者问题

    Posix条件变量 int pthread_cond_init(pthread_cond_t *cond, pthread_condattr_t *cond_attr); int pthread_co ...

  2. 并发编程(一): POSIX 使用互斥量和条件变量实现生产者/消费者问题

    boost的mutex,condition_variable非常好用.但是在Linux上,boost实际上做的是对pthread_mutex_t和pthread_cond_t的一系列的封装.因此通过对 ...

  3. POSIX 使用互斥量和条件变量实现生产者/消费者问题

    boost的mutex,condition_variable非常好用.但是在Linux上,boost实际上做的是对pthread_mutex_t 和pthread_cond_t的一系列的封装.因此通过 ...

  4. 并发编程入门(一): POSIX 使用互斥量和条件变量实现生产者/消费者问题

    boost的mutex,condition_variable非常好用.但是在Linux上,boost实际上做的是对pthread_mutex_t和pthread_cond_t的一系列的封装.因此通过对 ...

  5. 第四十章 POSIX条件变量

    条件变量 当一个线程互斥地访问某个变量时,它可能发现在其它线程改变状态之前,它什么也做不了 例如一个线程访问队列时,发现队列为空,它只能等待,只到其它线程将一个节点添加到队列中.这种情况就需要用到条件 ...

  6. POSIX条件变量

    条件变量: 当一个线程互斥的访问某个变量时,它可能发现其他线程改变状态之前,它什么都做不了例如:一个线程访问队列时,发现队列为空,它只能等待,直到其他线程将一个节点添加到队列中,这种情况就需要使用条件 ...

  7. posix 条件变量与互斥锁 示例生产者--消费者问题

    一.posix 条件变量 一种线程间同步的情形:线程A需要等某个条件成立才能继续往下执行,现在这个条件不成立,线程A就阻塞等待,而线程B在执行过程中使这个条件成立了,就唤醒线程A继续执行. 在pthr ...

  8. python条件变量之生产者与消费者操作实例分析

    python条件变量之生产者与消费者操作实例分析 本文实例讲述了python条件变量之生产者与消费者操作.分享给大家供大家参考,具体如下: 互斥锁是最简单的线程同步机制,面对复杂线程同步问题,Pyth ...

  9. java多线程解决生产者消费者问题

    import java.util.ArrayList; import java.util.List; /** * Created by ccc on 16-4-27. */ public class ...

随机推荐

  1. POJ 1286

    Burnside定理. 可以用Euler函数优化. #include <iostream> #include <cstdio> #include <cstring> ...

  2. Google翻译PDF文档

    Google翻译PDF文档 翻译软件虽多如牛毛,但有关整段/全文翻译,堪用的软件极少, 涉及专业技术的文献.胜任翻译工作的人力稀缺.少不了project师讴心沥血. 由于多是PDF格式.即使要翻译个概 ...

  3. debian mysql 定时自己主动备份的脚本

    #!/bin/sh LOG=/var/log/mysql-backup.log # mysql db info USER_ROOT=XXXXXX USER_PWD=XXXXXXX # mysql da ...

  4. STM32F407VG (四)时钟配置

    1.STM32 F407VG 的starup_stm32f40_41xxx.s的例如以下位置调用 IMPORT SystemInit,之后调用main函数,所以 进入main函数时候就已经自己主动完毕 ...

  5. BZOJ 1007: [HNOI2008]水平可见直线 平面直线

    1007: [HNOI2008]水平可见直线 Description 在xoy直角坐标平面上有n条直线L1,L2,...Ln,若在y值为正无穷大处往下看,能见到Li的某个子线段,则称Li为可见的,否则 ...

  6. 一个人的旅行 HDU杭电2066【dijkstra算法 || SPFA】

    pid=2066">http://acm.hdu.edu.cn/showproblem.php? pid=2066 Problem Description 尽管草儿是个路痴(就是在杭电 ...

  7. kibana智能检索发送多次_msearch —— 配置index pattern,同时设置时间段,就知道到底是在哪些索引里去查找数据了

    kibanasite/elasticsearch/log-*/_field_stats?level=indices      返回: {"_shards":{"total ...

  8. xBIM 高级01 IFC多模型合并

    系列目录    [已更新最新开发文章,点击查看详细]  多模型合并可以实现以下功能: 覆盖多个模型以表现得像一个模型 统一访问数据,就像它是单个模型一样 只读.要修改模型的内容,您必须使用特定模型 不 ...

  9. excel文件使用html导出

    <table><tr><td>1</td></tr><tr><td>2</td></tr>& ...

  10. Servlet学习(三)——实例:用户登录并记录登陆次数

    1.前提:在Mysql数据库下建立数据库web13,在web13下创建一张表user,插入几条数据如下: 2.创建HTML文件,命名为login,作为登录界面(以post方式提交) <!DOCT ...