Linux操作系统实验:生产者和消费者问题

2023-05-16

一、实验目的及要求

“生产者消费者”问题是一个著名的同时性编程问题的集合。通过编写经典的”生产者消费者”问题的实验,读者可以进一步熟悉 Linux 中多线程编程,并且掌握用信号量处理线程间的同步互斥问题。

二、实验仪器设备与软件环境

VMware Workstation Pro

三、实验过程及实验结果分析

“生产者消费者”问题描述如下。 有一个有限缓冲区和两个线程:生产者和消费者。他们分别把产品放入缓冲区和从缓冲区中 拿走产品。当一个生产者在缓冲区满时必须等待,当一个消费者在缓冲区空时也必须等待。 它们之间的关系如下图所示:
在这里插入图片描述

这里要求用有名管道来模拟有限缓冲区,用信号量来解决生产者消费者问题中的同步和互斥问题。

(1) 使用信号量解决

实验结果:
在这里插入图片描述
实验代码:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<fcntl.h>
#include<errno.h>
#include<pthread.h>
#include<semaphore.h>
#include<sys/ipc.h>
#include<sys/types.h>
#include<sys/stat.h>
#define MYFIFO        "myfifo"    /*缓冲区有名管道的名字*/
#define BUFFER_SIZE        3        /*缓冲区的单元数*/
#define UNIT_SIZE    6            /*每个单元的字节大小*/
#define RUN_TIME    30            /*运行时间*/
#define DELAY_TIME_LEVELS    5.0    /*周期的最大值*/

int fd;  /*管道描述符*/
time_t end_time;  /*存放线程的起始时间*/
sem_t mutex,full,avail;  /*信号量描述符*/

/*生产者线程*/
void *producer(void *arg)
{
    int real_write;  /*实际写入字节数*/
    int delay_time=0;

    /*time(NULL)返回从公元1970年1月1日的UTC时间0时0分0秒算起
 到现在所经过的秒数,while()的意思就是说如果在执行生产者线程的
 那一刻没有超过其结束时间,那么则执行*/
    while(time(NULL)<end_time)
    {
        delay_time=(int)(rand()*DELAY_TIME_LEVELS/(RAND_MAX)/2.0)+1;
        sleep(delay_time);
        /*P操作信号量 avail 和 mutex */   
        sem_wait(&avail);
        sem_wait(&mutex);
        printf("\nProducer:delay=%d\n",delay_time);
        /*生产者写入数据*/
        if((real_write=write(fd,"hello",UNIT_SIZE))==-1)
        {  
            /*这个errno=EAGAIN表示的是你的write本来是非阻塞情况,现在没有数
 据可读,这个时候就会置全局变量errno为EAGINA,表示可以再次进行读
 操作;如果是阻塞情况,那么被中断的话,errno=EINTR*/
            if(errno==EAGAIN)
            {
                printf("The FIFO has not been read yet.Please try later\n");
            }
        }
        else
        {
            printf("Write %d to the FIFO\n",real_write);
        }
        /*V操作信号量full和mutex*/
        sem_post(&full);
        sem_post(&mutex);
    }
    pthread_exit(NULL);
}

/*消费者线程*/
void *customer(void *arg)
{
    unsigned char read_buffer[UNIT_SIZE];
    int real_read;
    int delay_time;

    while(time(NULL)<end_time)
    {
        delay_time=(int)(rand()*DELAY_TIME_LEVELS/(RAND_MAX))+1;
        sleep(delay_time);
        /*P操作信号量full和mutex*/
        sem_wait(&full);
        sem_wait(&mutex);
        memset(read_buffer,0,UNIT_SIZE);
        printf("\nCustomer:delay=%d\n",delay_time);
    
        if((real_read=read(fd,read_buffer,UNIT_SIZE))==-1)
        {
            if(errno==EAGAIN)
            {
                printf("No data yet\n");
            }
        }
        printf("Read %s from FIFO\n",read_buffer);
        /*V操作信号量avail和mutex*/
        sem_post(&avail);
        sem_post(&mutex);
    }
    pthread_exit(NULL);
}

//主函数

int main()
{
    pthread_t thrd_pro_id,thrd_cus_id;
    pthread_t mon_th_id;
    int ret;

    srand(time(NULL));/*随机数发生器初始化*/
    end_time=time(NULL)+RUN_TIME;
    /*创建有名管道*/
    if((mkfifo(MYFIFO,O_CREAT|O_EXCL)<0)&&(errno!=EEXIST))
    {
        printf("Cannot create fifo\n");
        return errno;
    }
    /*打开管道*/
    fd=open(MYFIFO,O_RDWR,0666);
    if(fd==-1)
    {
        printf("Open fifo error\n");
        return fd;
    }
    
    /*初始化互斥信号量为1*/
    ret=sem_init(&mutex,0,1);
    /*初始化avail信号量为N*/
    ret+=sem_init(&avail,0,BUFFER_SIZE);
    /*初始化full信号量为0*/
    ret+=sem_init(&full,0,0);
    if(ret!=0)
    {
        printf("Any semaphore initialization failed\n");
        return ret;
    }
    
    /*创建两个进程*/
    ret=pthread_create(&thrd_pro_id,NULL,producer,NULL);
    if(ret!=0)
    {
        printf("Create producer thread error\n");
        return ret;
    }
    ret=pthread_create(&thrd_cus_id,NULL,customer,NULL);
    if(ret!=0)
    {
        printf("Create producer thread error\n");
        return ret;
    }
    pthread_join(thrd_pro_id,NULL);
    pthread_join(thrd_cus_id,NULL);
    close(fd);
//    unlink(MYFIFO);  /*所有打开该文件的进程都结束时文件被删除*/
    return 0;
}

(2)思考使用条件变量解决

实验结果:
在这里插入图片描述
在这里插入图片描述
实验代码:

 #include <stdio.h>
 #include <pthread.h>
 #define BUFFER_SIZE 4
 #define OVER (-1)
 struct producers//定义生产者条件变量结构
 {
 	int buffer[BUFFER_SIZE];
	pthread_mutex_t lock;
 	int readpos, writepos;
 	pthread_cond_t notempty;
 	pthread_cond_t notfull;
 };
 //初始化缓冲区
 void init(struct producers *b)
 {
 	pthread_mutex_init(&b->lock,NULL);
 	pthread_cond_init(&b->notempty,NULL);
 	pthread_cond_init(&b->notfull,NULL);
 	b->readpos=0;
 	b->writepos=0;
 }
 //在缓冲区存放一个整数
 void put(struct producers *b, int data)
 {
 	pthread_mutex_lock(&b->lock);
 //当缓冲区为满时等待
 	while((b->writepos+1)%BUFFER_SIZE==b->readpos)
 	{
 		pthread_cond_wait(&b->notfull,&b->lock);
 	}
 	b->buffer[b->writepos]=data;
 	b->writepos++;
 	if(b->writepos>=BUFFER_SIZE) b->writepos=0;
 	//发送当前缓冲区中有数据的信号
 	pthread_cond_signal(&b->notempty);
 	pthread_mutex_unlock(&b->lock);
 }
 
 int get(struct producers *b)
 {
 	int data;
 	pthread_mutex_lock(&b->lock);
 	while(b->writepos==b->readpos)
 	{
 	pthread_cond_wait(&b->notempty,&b->lock);
 	}
 	data=b->buffer[b->readpos];
 	b->readpos++;
 	if(b->readpos>=BUFFER_SIZE) b->readpos=0;
 	pthread_cond_signal(&b->notfull);
 	pthread_mutex_unlock(&b->lock);
 	return data;
 }
 struct producers buffer;
 void *producer(void *data)
 {
 	int n;
 	for(n=0;n<10;n++)
 	{
 	printf("Producer : %d-->\n",n);
 	put(&buffer,n);
 	}
 	put(&buffer,OVER);
 	return NULL;
 }
 
 void *consumer(void *data)
 {
 	int d;
 	while(1)
 	{
 	d=get(&buffer);
 	if(d==OVER) break;
 	printf("Consumer: --> %d\n",d);
 	}
 return NULL;
 }

 int main()
 {
 	pthread_t tha,thb;
 	void *retval;
 	init(&buffer);
 	pthread_create(&tha,NULL,producer,0);
 	pthread_create(&thb,NULL,consumer,0);
 	pthread_join(tha,&retval);
 	pthread_join(thb,&retval);
 	return 0;
 }

特别注意:如果运行时出现这种情况:
在这里插入图片描述
说明此时你并没有权限,上个权限就好了(sudo -s)
在这里插入图片描述
【上知乎搜:乘风与你渡晚舟】
csdn网站与知乎网站同作者

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Linux操作系统实验:生产者和消费者问题 的相关文章

  • C++ std::ref————详解

    想学习ref xff0c 必须先学习reference rapper 1 是什么 xff1f ref是个函数模板 xff1a 用来构建一个reference wrapper对象并返回 xff0c 该对象拥有传入的elem变量的引用 如果参数
  • I/O复用的高级应用:聊天室程序———实例代码

    1概述 这是一个聊天室程序 xff0c 分为服务端和客户端两部分 多个客户端可以连接到同一个服务器 xff0c 当一个客户端向服务器发送消息时 xff0c 该消息会被转发给除发送端外的其他客户端 xff0c 其他客户端收到该消息并输出到标准
  • CMake指令解析 set(CMAKE_CXX_FLAGS “$ENV{CXXFLAGS} -rdynamic -O3 -fPIC -ggdb -std=c++11 -Wall -Wno-deprec

    完整代码 set span class token punctuation span CMAKE CXX FLAGS span class token string 34 span class token variable ENV span
  • vscode找不到头文件报错,就离谱

    最近在vscode写一个项目 xff0c 进行编译测试的时候发现死活找不到头文件 xff0c 就离谱 xff0c CMakeLists txt里的include directories所有头文件包含路径写的明明白白清清楚楚 xff0c 就是
  • 有26个字母a~z,找出所有字母组合,a、b、c、ab、abc、a~z 都是一个组合(顺序无关)

    mark 一下 xff0c 好像是用深搜做的 xff0c 目前看不太懂 span class token keyword int span list span class token punctuation span span class
  • 对顶堆模板:求动态数组的中位数

    模板 priority queue span class token operator lt span span class token keyword int span span class token operator gt span
  • C++八股文

    文章目录 C 43 43 语言int function int a int b 指针数组和数组指针的区别 xff1f 数组指针指针数组 函数指针和指针函数的区别函数指针指针函数 常量指针和指针常量的区别数组和指针的区别指针和引用的区别数组名
  • 一个HTML网页简单有效的验证码更换方法

    代码展示 lt img name 61 34 verifycode 34 src 61 34 verifyServlet 34 height 61 34 40px 34 width 61 34 150px 34 onclick 61 34
  • 获取CSDN文章内容并转换为markdown文本的python

    这篇文章主要介绍了自己写的小工具 xff0c 可以直接获取csdn文章并转换为markdown格式 需要的朋友可以参考下 自己写的小工具 xff0c 可以直接获取csdn文章并转换为markdown格式 效果图 核心代码 span clas
  • Android-视图绑定

    举例 xff1a 此时 xff0c first layout xml中定义了一个button且id为button1的按钮 在FirstActivity中我们想要调用这个按钮的话 xff0c 有两种方法 第一种 xff0c 通过FindVie
  • C语言程序设计1

    C语言程序设计1 计算机语言分类 xff1a 机器语言 xff1a xff08 machine language xff09 计算机直接使用的二进制形式的程序语言或机器代码 汇编语言 xff1a 借助助记符进行描述的计算机语言 高级语言 x
  • ZYNQ中的GPIO与AXI GPIO

    GPIO GPIO 一种外设 xff0c 对器件进行观测和控制MIO 将来自PS外设和静态存储器接口的访问多路复用到PS引脚上处理器控制外设的方法 通过一组寄存器包括状态寄存器和控制寄存器 xff0c 这些寄存器都是有地址的 xff0c 通
  • FTP文件传输协议

    简介 FTP协议 xff1a 文件传输协议 xff08 File Transfer Protocol xff09 协议定义了一个在远程计算机系统和本地计算机系统之间传输文件的一个标准FTP运行在OSI模型的应用层 xff0c 并利用传输协议
  • python中如何用for循环语句1加到100?

    计算机是现代一种用于高速计算的电子计算机器 xff0c 是一种高级的计算工具 可以进行数值计算 xff0c 又可以进行逻辑计算 xff0c 还具有存储记忆功能 是能够按照程序运行 xff0c 自动 高速处理海量数据的现代化智能电子设备 计算
  • controller层配置全局配置拦截器

    大家好 xff0c 我是一名在算法之路上不断前进的小小程序猿 xff01 体会算法之美 xff0c 领悟算法的智慧 希望各位博友走过路过可以给我点个免费的赞 xff0c 你们的支持是我不断前进的动力 xff01 xff01 加油吧 xff0
  • 用python写DFS和BFS算法

    前言 xff1a 菜鸟学算法 加油 xff01 一 什么是DFS和BFS xff1f 1 BFS算法 xff1a 宽度优先搜索算法 xff08 又称广度优先搜索 xff09 是最简便的图的搜索算法之一 xff0c 这一算法也是很多重要的图的
  • 进程同步 生产者消费者问题

    题目 xff1a 某超级市场 xff0c 可容纳100人同时购物 入口处备有篮子 xff0c 每个购物者可持一只篮子入内购物 出口处结帐 xff0c 并归还篮子 xff08 出 入口仅容一人通过 xff09 请试用P xff08 S xff
  • Windows-取消锁屏密码

    开始 gt 设置 gt 账户 gt 登录选项 gt 密码 gt 输入当前密码 gt 更改密码 xff08 默认为空就行 xff09 gt 下一步 gt 完成
  • 腾讯云4核服务器和2核区别大吗?性能差异

    腾讯云服务器2核和4核性能有什么区别 xff1f 云服务器核数指的是vCPU处理器 xff0c 云服务器CPU核心数如何选择主要取决于用户实际应用情况 xff0c 如果当前应用对CPU计算能力要求不高 xff0c 2核完全可以胜任 xff0
  • 最详细的手工LAMP环境搭建

    环境 xff1a 阿里云服务器ECS xff0c Alibaba Cloud Linux 3 2104 LTS 64位 xff0c 2核 vCPU 2 GiB LAMP 是搭建Web应用时最常用的环境 xff0c LAMP 分别表示 Lin

随机推荐

  • python 语音播报 简单入门

    coding utf 8 import pyttsx3 import time 初始化 pt 61 pyttsx3 init 说什么 pt say 34 你好 xff0c dbirder 34 开始说吧 pt runAndWait time
  • 【optimizer详解】

    optimizer 定义 optimizer就是在深度学习反向传播过程中 xff0c 指引损失函数 xff08 目标函数 xff09 的各个参数往正确的方向更新合适的大小 xff0c 使得更新后的各个参数让损失函数 xff08 目标函数 x
  • docker网络配置

    开放容器端口 执行docker run的时候有个 p选项 xff0c 可以将容器中的应用端口映射到宿主机中 xff0c 从而实现让外部主机可以通过访问宿主机的某端口来访问容器内应用的目的 p选项能够使用多次 xff0c 其所能够暴露的端口必
  • Ubuntu使用SSH工具默认用root用户连接;解决SSH不能用root用户连接。

    ROOT是什么意思 xff1f Root xff0c 也称为根用户 xff0c 是Unix 如 Solaris AIX BSD xff09 和类UNIX系统 如 Linux QNX 等 xff0c 及Android和iOS移动设备系统中的唯
  • LeetCode55. 跳跃游戏(贪心)

    力扣 解题思路 xff1a 1 设想一下 xff0c 对于数组中的任意一个位置 y xff0c 我们如何判断它是否可以到达 xff1f 根据题目的描述 xff0c 只要存在一个位置 x xff0c 它本身 可以到达 xff0c 并且它跳跃的
  • LeetCode300. 最长递增子序列(动态规划 / 贪心)

    力扣 解题思路 xff1a 1 动态规划 状态定义 xff1a dp i 的值代表 nums 以 nums i 结尾的最长子序列长度 转移方程 xff1a 设 j 0 i j 0 i xff0c 考虑每轮计算新 dp i 时 xff0c 遍
  • LeetCode299. 猜数字游戏

    力扣 解题思路 1 使用一个vector flag 记录哪个位置的下的字符相同 xff0c 使用一个Hash map记录secret中剩余字符与次数的映射 2 遍历guess 找到guess中的字符与 secret 相同但是在不同位置的字符
  • 八大排序 - (详解)

    目录 一 直接插入排序 1 思想 2 实现 3 特性总结 二 希尔排序 1 思想 2 实现 3 特性总结 三 选择排序 1 思想 2 实现 3 特性总结 四 堆排序 1 思想 2 实现 3 特性分析 五 冒泡排序 1 思想 2 实现 3 特
  • 牛客 - 另类加法

    另类加法 解题思路 1 二进制位异或运算相当于对应位相加 xff0c 不考虑进位 比如 xff1a 1 1 61 0 gt 1 43 1 61 0 当前位值为0 xff0c 进一位 1 0 61 1 gt 1 43 0 61 1 当前位值为
  • Jmeter添加MD5方法插件

    1 xff1a 下载 https jmeter plugins org install Install 2 xff1a jmeter plugins manager 1 3 jar放到 apache jmeter 5 0 lib ext目录
  • Linux常用指令(详解)

    目录 1 ls指令 2 pwd 3 clear 4 whoami 5 cd 6 tree 7 mkdir 8 touch 9 rmdir 10 rm 11 man 12 cp 13 mv 14 cat 15 more 16 less 17
  • 进程间通信详解

    目录 一 进程间通信介绍 1 进程间通信的目的 2 进程间通信的本质 3 进程间通信分类 二 什么是管道 三 匿名管道 1 匿名管道只能用于具有亲缘关系的进程之间进行通信 xff0c 常用于父子 2 pipe函数 3 匿名管道的使用 4 管
  • 大厂笔试真题

    1 复数相乘 2 K个一组翻转链表 include lt iostream gt include lt vector gt include lt string gt using namespace std void Reverse vect
  • 文件系统概念

    1 文件逻辑结构 1 有结构文件和无结构文件 定长记录 可变长记录 2 顺序文件 3 索引文件 4 索引顺序文件 5 多级索引顺序文件 2 文件目录 1 文件控制块 2 目录结构 3 索引节点 3 文件的物理结构 1 文件块 xff0c 磁
  • Makefile

    1 基本规则 目标 依赖 目标 要生成的目标文件 tab 命令 依赖 目标文件由那些文件生成 命令 通过执行该命令由依赖文件生成目标 举例 add o add c gcc c add c o add c 1 其他规则 目标的时间必须晚于依赖
  • 计算机组成原理测试题

    随堂测试 1 单项选择题 第1题 主频为10MHZ xff0c 则时钟周期为 10ns 100ns xff08 答案 xff09 1000ns 第2题 冯 诺伊曼机工作方式的基本特点是 D 存储器按内容选择地址 C 堆栈操作 B 按地址访问
  • js练习题(3)

    1 序列 xff1a 1 xff0c 2 xff0c 3 xff0c 5 xff0c 8 xff0c 13 找出第20个数是多少 得出前20个数之和是多少 xff1f span class token keyword function sp
  • JAVA 两数求商

    题目描述 xff1a 给定两个整数 a 和 b xff0c 求它们的除法的商 a b xff0c 要求不得使用乘号 除号 以及求余符号 注意 xff1a 整数除法的结果应当截去 xff08 truncate xff09 其小数部分 xff0
  • 约瑟夫环总结

    约瑟夫环 N个人围成一圈 xff0c 从第一个人开始报数 xff0c 报到m的人出圈 xff0c 剩下的人继续从1开始报数 xff0c 报到m的人出圈 xff0c 如此往复 问题一 xff1a 所有人都出圈 xff0c 求出圈的人的编号顺序
  • Linux操作系统实验:生产者和消费者问题

    一 实验目的及要求 生产者消费者 问题是一个著名的同时性编程问题的集合 通过编写经典的 生产者消费者 问题的实验 xff0c 读者可以进一步熟悉 Linux 中多线程编程 xff0c 并且掌握用信号量处理线程间的同步互斥问题 二 实验仪器设