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网络编程--网络知识介绍客户端和服务端 网络程序和普通的程序有一个最大的区别是网络程序是由两个部分组成的--客户端和服务器端. 客户 ...
随机推荐
- 解锁网络编程之NIO的前世今生
个人博客网:https://wushaopei.github.io/ (你想要这里多有) NIO 内容概览: NIO 网络编程模型 NIO 网络编程详解 NIO 网络编程实战 NIO 网络编程缺 ...
- (Java实现) 洛谷 P1098 字符串的展开
import java.util.ArrayList; import java.util.Scanner; public class zifuchuandezhankai { static Array ...
- Java实现 LeetCode 741 摘樱桃(DFS || 递推 || 传纸条)
741. 摘樱桃 一个N x N的网格(grid) 代表了一块樱桃地,每个格子由以下三种数字的一种来表示: 0 表示这个格子是空的,所以你可以穿过它. 1 表示这个格子里装着一个樱桃,你可以摘到樱桃然 ...
- Java实现 LeetCode 390 消除游戏
390. 消除游戏 给定一个从1 到 n 排序的整数列表. 首先,从左到右,从第一个数字开始,每隔一个数字进行删除,直到列表的末尾. 第二步,在剩下的数字中,从右到左,从倒数第一个数字开始,每隔一个数 ...
- Java实现 蓝桥杯VIP 算法训练 连接字符串
算法训练 连接字符串 时间限制:1.0s 内存限制:512.0MB 编程将两个字符串连接起来.例如country与side相连接成为countryside. 输入两行,每行一个字符串(只包含小写字母, ...
- Java实现 LeetCode 98 验证二叉搜索树
98. 验证二叉搜索树 给定一个二叉树,判断其是否是一个有效的二叉搜索树. 假设一个二叉搜索树具有如下特征: 节点的左子树只包含小于当前节点的数. 节点的右子树只包含大于当前节点的数. 所有左子树和右 ...
- java实现第五届蓝桥杯LOG大侠
LOG大侠 atm参加了速算训练班,经过刻苦修炼,对以2为底的对数算得飞快,人称Log大侠. 一天,Log大侠的好友 drd 有一些整数序列需要变换,Log大侠正好施展法力- 变换的规则是: 对其某个 ...
- Git Gui工具从远程克隆代码总是提示路径已经存在。问题完美解决!
最近使用Git Gui工具从远程克隆代码总是提示路径已经存在,提示如下图, 原因是使用Git Guii克隆代码时的路径不能是选择一个已经建好的目录(D盘的project下的test文件夹是我提前建好的 ...
- FTP服务器上传工具,FTP服务器上传工具下载!
IIS7服务器管理工具能够作为FTP的客户端,进行FTP的命令操作,可在客户端,下载,安装FTP软件! 同时,它也可以作为VNC的客户端,进行VNC的命令操作!它能够批量连接Windows和Linux ...
- Java基础(八)
一.Java集合框架 Java集合类库也将接口与实现分离. 队列接口指出可以在队列的尾部添加元素,在队列的头部删除元素,并且可以查找队列中元素的个数. 队列通常有两种实现方式:一种是使用循环数组:另一 ...