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

假设有两个线程同时访问全局变量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. JAVA自学笔记(1)

    JAVA入门级知识储备(一) 1.Scanner的欢乐接收 import java.util.Scanner; public class first { public static void main ...

  2. 04.Django-视图与路由

    视图层 1. HTTP请求 HttpRequest对象 request.path #使用GET方法时,只会得到路径. request.get_full_path() #使用GET方法时,会得到包括路径 ...

  3. 通过一个vue+elementUI的小实例来讲解一下它们是如何使用的

    需求:点击一个按钮,弹出一个模态框,这个模态框有两个tab,tab中是各种报警条件,这些报警条件是从数据库中动态取出的,数据库中数据变更后,这个界面也要变更,我们可以查看和编辑这些报警条件.底部“确定 ...

  4. HDL-数字电路建模的要点

    https://mp.weixin.qq.com/s/tEDMWf1gk0e7u4hIWKM9bQ   ​​   一. 拓扑   数字电路的拓扑抽象出来之后比较简单,就是线(Wire)和开关(Swit ...

  5. 【Tomcat】JSP使用Session、Cookie实现购物车

    购物界面shop.jsp 初始页面 添加商品后,在session中设置属性,重定向回到shop.jsp,然后根据session的内容显示结果 Cookie设置setMaxAge可以延长session的 ...

  6. 数组API汇总

    数组API汇总   Javascript数组API: 1.将数组转化为字符串:2种: 1.var str=String(str); 将数组转化为字符串并分隔每个元素; var arr=[1,2,3]; ...

  7. Java实现 蓝桥杯VIP 算法提高 Quadratic Equation

    算法提高 Quadratic Equation 时间限制:1.0s 内存限制:512.0MB 问题描述 求解方程ax2+bx+c=0的根.要求a, b, c由用户输入,并且可以为任意实数. 输入格式: ...

  8. Java实现 洛谷 P1047 校门外的树

    import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner sc = ...

  9. mac下使用VMVARE安装win10虚拟机的一些坑

    最近Mac上安装windows踩到了几个坑: 坑一:启动虚拟机后,提示找不到CD-ROM中找不到对应的ISO文件 硬盘格式请选择 在虚拟机->设置中选择启动磁盘为CD_ROM,然后重新启动. 坑 ...

  10. 《刻意练习之C#》-0016- C#预处理器指令

    预处理指令 这些指令/命令不会转换为可执行代码,但会影响编译过程的各个方面:列如,可以让编译器不编译某一部分代码等. C#中主要的预处理指令 #define和#undef #define指令定义: # ...