举一个列子来说明条件变量:

假设有两个线程同时访问全局变量n,初始化值是0,

一个线程进入临界区,进行互斥操作,线程当n大于0的时候才执行下面的操作,如果n不大于0,该线程就一直等待。

另外一个线程也是进入临界区,修改n的值,当修改了n的值后,需要向等待中的线程发送通知,修改了n的值。但是现在存在这样的一个问题:当第一个线程进入临界区的时候,第一个线程一直处在等待n改变的状态,第二个线程是无法进入临界区的修改n的值的,这样第一个线程

就处于死锁了。上面这个问题可以时候条件变量来解决。

条件变量也可以用于生产者和消费者的状态:

假设一个线程访问一个队列该队列是空的,那么该线程只能处于阻塞状态,直到其他线程将一个产品添加到队列中,发现通知通知等待的线程

对于等待条件的代码,首先需要锁定互斥量,因为这个条件变量是多个线程都可以同时访问的,所以需要进行互斥,这里使用while 等待只要条件为假,该线程就一直处于等待状态

对于给条件发现信号的代码:首先也是需要进行互斥,然后设置条件为真,然后给等待的线程发一个通知

下面我们使用条件变量来进行生产者与消费者的问题

int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr);

pthread_cond_init函数可以用来初始化一个条件变量。他使用变量attr所指定的属性来初始化一个条件变量,如果参数attr为空,那么它将使用缺省的属性来设置所指定的条件变量。

pthread_cond_destroy函数可以用来摧毁所指定的条件变量,同时将会释放所给它分配的资源。调用该函数的进程也并不要求等待在参数所指定的条件变量上。

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

cond 条件变量

mutex 互斥锁

第一个参数*cond是指向一个条件变量的指针。第二个参数*mutex则是对相关的互斥锁的指针。

int pthread_cond_signal(pthread_cond_t *cond);

int pthread_cond_broadcast(pthread_cond_t *cond);

参数*cond是对类型为pthread_cond_t 的一个条件变量的指针。当调用pthread_cond_signal时一个在相同条件变量上阻塞的线程将被解锁。如果同时有多个线程阻塞,则由调度策略确定接收通知的线程。如果调用pthread_cond_broadcast,则将通知阻塞在这个条件变量上的所有线程。一旦被唤醒,线程仍然会要求互斥锁。如果当前没有线程等待通知,则上面两种调用实际上成为一个空操作。如果参数*cond指向非法地址,则返回值EINVAL。

#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() #define CONSUMERS_COUNT 1
#define PRODUCERS_COUNT 1
#define BUFFSIZE 10 //首先定义一个条件变量
pthread_cond_t g_cond; unsigned short in = ;
unsigned short out = ;
unsigned short produce_id = ;
unsigned short consume_id = ;
int nReady = ;//表示当前产生的数目的计数器
pthread_mutex_t g_mutex; pthread_t g_thread[CONSUMERS_COUNT + PRODUCERS_COUNT]; void *consume(void *arg)
{
int i;
int num = (int)arg;
while ()
{
// 首先需要进行互斥
pthread_mutex_lock(&g_mutex);
while(nReady == ){//等待产品不为空
//条件变量需要和互斥锁进行配合使用
printf("consume thread_id %d now is waiting for .....\n",num);
pthread_cond_wait(&g_cond,&g_mutex);
}
printf("consume thread_id %d now is begin consume product \n",num);
//消费产品,将产品数据减一
nReady = nReady -;
pthread_mutex_unlock(&g_mutex);
sleep(); }
return NULL;
} void *produce(void *arg)
{
int num = (int)arg;
int i;
while ()
{
// 首先需要进行互斥
pthread_mutex_lock(&g_mutex);
//开始生产产品
nReady = nReady +;
//发起通知
printf("producter thread_id %d now is singal for consume .....\n",num);
pthread_cond_signal(&g_cond);
pthread_mutex_unlock(&g_mutex);
sleep();
}
return NULL;
} int main(void)
{
int i; //初始化一个互斥锁
pthread_mutex_init(&g_mutex, NULL);
//初始化条件变量
pthread_cond_init(&g_cond,NULL); for (i = ; i < CONSUMERS_COUNT; i++)
pthread_create(&g_thread[i], NULL, consume, (void *)i); for (i = ; i < PRODUCERS_COUNT; i++)
pthread_create(&g_thread[CONSUMERS_COUNT + i], NULL, produce, (void *)i); for (i = ; i < CONSUMERS_COUNT + PRODUCERS_COUNT; i++)
pthread_join(g_thread[i], NULL); //销毁互斥锁
pthread_mutex_destroy(&g_mutex);
//销毁条件变量
pthread_cond_destroy(&g_mutex); return ;
}

编译下代码:

gcc product.c -o product -lpthread

运行代码:

./product

代码中生产者和消费者都只有一个线程

我们来看程序运行的结果:

pthread_cond_wait前要先加锁
     pthread_cond_wait内部会解锁,然后等待条件变量被其它线程激活
     pthread_cond_wait被激活后会再自动加锁

pthread_cond_wait的内部实现流程:

1、第一步首先对互斥锁进行解锁

2、第二步等待其他线程改变条件变量

3、然后自动加锁后退出等待

linux网络编程-posix条件变量(40)的更多相关文章

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

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

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

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

  3. linux网络编程-posix信号量与互斥锁(39)

    -posix信号量信号量 是打开一个有名的信号量 sem_init是打开一个无名的信号量,无名信号量的销毁用sem_destroy sem_wait和sem_post是对信号量进行pv操作,既可以使用 ...

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

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

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

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

  6. Linux多线程实践(六)使用Posix条件变量解决生产者消费者问题

    前面的一片文章我们已经讲过使用信号量解决生产者消费者问题.那么什么情况下我们须要引入条件变量呢? 这里借用  http://www.cnblogs.com/ngnetboy/p/3521547.htm ...

  7. Linux网络编程入门 (转载)

    (一)Linux网络编程--网络知识介绍 Linux网络编程--网络知识介绍客户端和服务端         网络程序和普通的程序有一个最大的区别是网络程序是由两个部分组成的--客户端和服务器端. 客户 ...

  8. [转] - Linux网络编程 -- 网络知识介绍

    (一)Linux网络编程--网络知识介绍 Linux网络编程--网络知识介绍客户端和服务端         网络程序和普通的程序有一个最大的区别是网络程序是由两个部分组成的--客户端和服务器端. 客户 ...

  9. 【转】Linux网络编程入门

    (一)Linux网络编程--网络知识介绍 Linux网络编程--网络知识介绍客户端和服务端         网络程序和普通的程序有一个最大的区别是网络程序是由两个部分组成的--客户端和服务器端. 客户 ...

随机推荐

  1. DDD之2领域概念

    图中是暗黑领域,非常牛逼的技能. 背景 DDD中出现的名词: 领域,子领域,核心域,通用域,支撑域,限界上下文,聚合,聚合根,实体,值对象 都是关键概念,但是又比较晦涩,在开始DDD之前,搞清楚这些关 ...

  2. PIX防火墙配置A/S故障切换

    PIX防火墙配置A/S故障切换 1.基本命令 failover show failover failover lan enable failover lan interface zwish e2 fa ...

  3. Rocket - config - DefaultConfig

    https://mp.weixin.qq.com/s/zWW00D0fb8h7_TotGD9YoQ   介绍DefaultConfig类的组成.     1. DefaultConfig   Defa ...

  4. Chisel3 - model - Builder

    https://mp.weixin.qq.com/s/THqyhoLbbuXXAtdQXRQDdA   介绍构建硬件模型的Builder.   1. DynamicContext   ​​ 动态上下文 ...

  5. 使用锚点定位不改变url同时平滑的滑动到锚点位置,不会生硬的直接到锚点位置

    使用锚点定位不改变url同时平滑的滑动到锚点位置,不会生硬的直接到锚点位置 对前端来说锚点是一个很好用的技术,它能快速定位到预先埋好的位置. 但是美中不足的是它会改变请求地址url,当用户使用了锚点的 ...

  6. 一篇文章带你吃透 Docker 原理

    容器的实现原理 从本质上,容器其实就是一种沙盒技术.就好像把应用隔离在一个盒子内,使其运行.因为有了盒子边界的存在,应用于应用之间不会相互干扰.并且像集装箱一样,拿来就走,随处运行.其实这就是 Paa ...

  7. Java实现 LeetCode 462 最少移动次数使数组元素相等 II

    462. 最少移动次数使数组元素相等 II 给定一个非空整数数组,找到使所有数组元素相等所需的最小移动数,其中每次移动可将选定的一个元素加1或减1. 您可以假设数组的长度最多为10000. 例如: 输 ...

  8. Java实现 LeetCode 30 串联所有单词的子串

    30. 串联所有单词的子串 给定一个字符串 s 和一些长度相同的单词 words.找出 s 中恰好可以由 words 中所有单词串联形成的子串的起始位置. 注意子串要与 words 中的单词完全匹配, ...

  9. java代码(3)----guava复写Object常用方法

    guava复写Object常用方法 Guava是一个Google的基于java1.6的类库集合的扩展项目,这个库提供用于集合,缓存,支持原语,并发性,字符串处理,I/O和验证的实用方法, 这些高质量的 ...

  10. 源码分析(4)-ConcurrentHashMap(JDK1.8)

    一.UML类图 ConcurrentHashMap键值不能为null:底层数据结构是数组+链表/红黑二叉树:采用CAS(比较并交换)和synchronized来保证并发安全. CAS文章:https: ...