linux网络编程-posix条件变量(40)

举一个列子来说明条件变量:
假设有两个线程同时访问全局变量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)的更多相关文章
- Linux多线程编程的条件变量
在stackoverflow上看到一关于多线程条件变量的问题,题主问道:什么时候会用到条件变量,mutex还不够吗?有个叫slowjelj的人做了很好的回答,我再看这个哥们其他话题的一些回答,感觉水平 ...
- Linux 多线程编程—使用条件变量实现循环打印
编写一个程序,开启3个线程,这3个线程的ID分别为A.B.C,每个线程将自己的ID在屏幕上打印10遍,要求输出结果必须按ABC的顺序显示:如:ABCABC….依次递推. 使用条件变量来实现: #inc ...
- linux网络编程-posix信号量与互斥锁(39)
-posix信号量信号量 是打开一个有名的信号量 sem_init是打开一个无名的信号量,无名信号量的销毁用sem_destroy sem_wait和sem_post是对信号量进行pv操作,既可以使用 ...
- linux网络编程之posix条件变量
今天来学习posix的最后一个相关知识----条件变量,言归正传. 下面用一个图来进一步描述条件变量的作用: 为什么呢? 这实际上可以解决生产者与消费者问题,而且对于缓冲区是无界的是一种比较理解的解决 ...
- Linux多线程实践(8) --Posix条件变量解决生产者消费者问题
Posix条件变量 int pthread_cond_init(pthread_cond_t *cond, pthread_condattr_t *cond_attr); int pthread_co ...
- Linux多线程实践(六)使用Posix条件变量解决生产者消费者问题
前面的一片文章我们已经讲过使用信号量解决生产者消费者问题.那么什么情况下我们须要引入条件变量呢? 这里借用 http://www.cnblogs.com/ngnetboy/p/3521547.htm ...
- Linux网络编程入门 (转载)
(一)Linux网络编程--网络知识介绍 Linux网络编程--网络知识介绍客户端和服务端 网络程序和普通的程序有一个最大的区别是网络程序是由两个部分组成的--客户端和服务器端. 客户 ...
- [转] - Linux网络编程 -- 网络知识介绍
(一)Linux网络编程--网络知识介绍 Linux网络编程--网络知识介绍客户端和服务端 网络程序和普通的程序有一个最大的区别是网络程序是由两个部分组成的--客户端和服务器端. 客户 ...
- 【转】Linux网络编程入门
(一)Linux网络编程--网络知识介绍 Linux网络编程--网络知识介绍客户端和服务端 网络程序和普通的程序有一个最大的区别是网络程序是由两个部分组成的--客户端和服务器端. 客户 ...
随机推荐
- 如何基于 echarts 在柱状图或条形图上实现转换率?(有想法吗?)
目录 需求 探索一 探索二 探索三 转换实践思路1 转换实践思路2 其他思路 探索四(揭晓答案) 答案篇说明 backgroundColor 用法 双柱合一 始终在轴的中间 百分在变,但是距离轴的距离 ...
- parrot os安装vmware pro
转载https://www.linuxtechi.com/install-vmware-workstation-14-debian-9/ Open the terminal and execute t ...
- 04 . Mysql主从复制和读写分离
Mysql AB复制 AB复制又称之为主从复制,用于实现数据同步,实现Mysql的AB复制时,数据库的版本尽量保持一致,如果不能保持一致,最起码从服务器的版本要高于主服务器,但是就无法实现双向复制 ...
- 非阻塞赋值(Non-blocking Assignment)是个伪需求
https://mp.weixin.qq.com/s/mH84421WDGRb7cuU5FEFIQ Verilog的赋值很是复杂,包括: 1. Continuous assignment; 2. Pr ...
- 前端HTML 定位position 绝对定位 相对定位
>>>position:absolute;绝对定位 当前元素相对于父级元素位置[该父级元素必须也设定了position,不然会继续往上找祖先元素,直到body为止]的定位 >& ...
- Mysql安装与设置用户名、密码
个人博客网:https://wushaopei.github.io/ (你想要这里多有) 关于MySQL程序中数据库调度的流程图解: 1-MySql数据库的安装 安装前要注意,看看当前系 ...
- Java实现 蓝桥杯 算法提高 计算超阶乘(暴力)
试题 算法提高 计算超阶乘 问题描述 计算1*(1+k)(1+2k)(1+3k)-(1+n*k-k)的末尾有多少个0,最后一位非0位是多少. 输入格式 输入的第一行包含两个整数n, k. 输出格式 输 ...
- (Java实现) 洛谷 P1098 字符串的展开
import java.util.ArrayList; import java.util.Scanner; public class zifuchuandezhankai { static Array ...
- Java实现 LeetCode 221 最大正方形
221. 最大正方形 在一个由 0 和 1 组成的二维矩阵内,找到只包含 1 的最大正方形,并返回其面积. 示例: 输入: 1 0 1 0 0 1 0 1 1 1 1 1 1 1 1 1 0 0 1 ...
- java实现 蓝桥杯 算法训练 操作格子
问题描述 有n个格子,从左到右放成一排,编号为1-n. 共有m次操作,有3种操作类型: 1.修改一个格子的权值, 2.求连续一段格子权值和, 3.求连续一段格子的最大值. 对于每个2.3操作输出你所求 ...