Linux 基本语句_9_C语言_生产者消费者

完整版生产者代码:

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/file.h> 
#include <string.h>#define MAXLEN 10
#define ALPHABET 1
#define ALPHABET_START 'a'
#define COUNT_OF_ALPHABET 26
#define DIGIT 2
#define DIGIT_START '0'
#define COUNT_OF_DIGIT 10
#define SIGN_TYPE ALPHABETconst char * fifo_file = "./FIFO.txt";char buf[MAXLEN];int lock_set(int fd, int type){struct flock old_lock, lock;lock.l_whence = SEEK_SET; //加锁区域为文件开始处 lock.l_start = 0;//加锁区域在文件位置的相对偏移量 lock.l_len = 0;//加锁区域长度 lock.l_type = type;//锁的类型 lock.l_pid = -1;fcntl(fd, F_GETLK, &lock);//写入if(lock.l_type != F_UNLCK){//若未解锁 if(lock.l_type == F_RDLCK){//读取锁 printf("Read lock already set by %d\n", lock.l_pid);}else if(lock.l_type == F_WRLCK){printf("Write lock already set by %d\n", lock.l_pid);} } /*上述可能由于不是解锁状态l_type被设置成了相应的锁值下方进行上锁操作时要再次调用type*/ lock.l_type = type;if((fcntl(fd, F_SETLKW, &lock)) < 0){//上锁失败 printf("Lock failed:type  = %d\n", lock.l_type);return -1;}switch(lock.l_type){case F_RDLCK:printf("Read lock set by %d\n", getpid());//获取当前进程的IDbreak;case F_WRLCK:printf("Write lock set by %d\n", getpid());break;case F_UNLCK:printf("Release lock by %d\n", getpid());//解锁返回1 return 1;break; }return 0;//上锁返回0 
}int product(void){int fd;unsigned int sign_type, sign_start, sign_count, size;static unsigned int counter = 0;//只会执行一次 if((fd = open(fifo_file, O_WRONLY|O_APPEND)) < 0){//只写方式打开 ,追加模式 perror("open error");return -1;}sign_type = SIGN_TYPE;//英文字符集合 switch(sign_type){case ALPHABET:sign_start = ALPHABEF_START;sign_count = COUNT_OF_ALPHABET;//26break;case DIGIT:sign_start = DIGIT_START;sign_count = COUNT_OF_DIGIT;break;default:return -1; }sprintf(buf, "%c", (sign_start + counter));//将字符写入buf缓冲区counter = (counter + 1) % sign_count;lock_set(fd, F_WRLCK);//写锁if((size = write(fd, buf, strlen(buf))) < 0){//打开失败,否者写入 perror("producer:write error");return -1; }lock_set(fd, F_UNLCK);//解锁close(fd);return 0; 
}int main(int argc, const char * argv[]){int time_step = 1;//周期 int time_life = 10;//生产数量close(open(fifo_file, O_REONLY|O_CREAT|O_TRUNC, 0664));//创建文件 if(argc > 1){sscanf(argv[1], "%d", &time_step);//将argv[1]转成整数存入time_step中 }if(argc > 2){sscanf(argv[2], "%d", &time_life);} while(time_life --){if(product() < 0){break;} sleep(time_step);}return 0;
}

流程:
在这里插入图片描述

原版代码有点缺失和问题,添加的代码如下:

原版代码缺少创建文件函数,以及没有对文件清空的函数
每次启动一轮生产,为了方便观察将文件上次生产的内容清空:

close(open(fifo_file, O_REONLY|O_CREAT|O_TRUNC, 0664));//创建文件&清空

文件打开模式必须是追加模式,否则生产的新数据会覆盖原有数据:

if((fd = open(fifo_file, O_WRONLY|O_APPEND)) < 0)

运行效果:

FIFO.txt文件上次运行时残留有数据
在这里插入图片描述

生产五个数据:
在这里插入图片描述
文件之前生产信息被清除,取而代之的是新数据:

在这里插入图片描述

完整版消费者代码:

 #include <stdio.h>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <unistd.h>#include <stdlib.h>#include <sys/file.h> #include <string.h>#define MAX_FILE_SIZE 100 * 1024 * 102const char *fifo_file  = "./FIFO.txt";const char *temp_file = "./temp";int lock_set(int fd, int type){struct flock old_lock, lock;lock.l_whence = SEEK_SET; //加锁区域为文件开始处 lock.l_start = 0;//加锁区域在文件位置的相对偏移量 lock.l_len = 0;//加锁区域长度 lock.l_type = type;//锁的类型 lock.l_pid = -1;fcntl(fd, F_GETLK, &lock);//写入if(lock.l_type != F_UNLCK){//若未解锁 if(lock.l_type == F_RDLCK){//读取锁 printf("Read lock already set by %d\n", lock.l_pid);}else if(lock.l_type == F_WRLCK){printf("Write lock already set by %d\n", lock.l_pid);}}                     /*上述可能由于不是解锁状态l_type被设置成了相应的锁值下方进行上锁操作时要再次调用type*/ lock.l_type = type;                                         if((fcntl(fd, F_SETLKW, &lock)) < 0){//上锁失败             printf("Lock failed:type  = %d\n", lock.l_type);return -1;}switch(lock.l_type){case F_RDLCK:printf("Read lock set by %d\n", getpid());//获取当前进程的IDbreak;                                                                     case F_WRLCK:printf("Write lock set by %d\n", getpid());break;case F_UNLCK:printf("Release lock by %d\n", getpid());//解锁返回1 return 1;break;}return 0;//上锁返回0 
}int customing(const char * myfifo, int need){int fd;char buf;int counter = 0;if((fd = open(myfifo, O_RDONLY)) < 0){//只读 perror("FunctI/On customing error");return -1;}printf("Enjoy:");lseek(fd, SEEK_SET, 0);while(counter < need){while((read(fd, &buf, 1) == 1) && (counter < need)){//read期望读取的字符数与实际所读一样&&.... fputc(buf, stdout);//打印到显示屏 counter ++;}}fputs("\n", stdout);close(fd);return 0;
}                                                                                                         int myfilecopy(const char * sour_file, const char * dest_file, int offset, int count, int copy_mode){int in_file, out_file;int counter = 0;char buff_unit;if((in_file = open(sour_file, O_RDONLY|O_NONBLOCK)) < 0){//非阻塞只读 perror("FunctI/On my filecopy error int source file\n");return -1;}if((out_file = open(dest_file, O_RDWR|O_CREAT|O_TRUNC|O_NONBLOCK, 0664)) < 0){//非阻塞&打开或创建 perror("FUNCTI/O myfilecopy error in destinatI/on file");return -1;}lseek(in_file, offset, SEEK_SET);//设置指针到指定位置while((read(in_file, &buff_unit, 1) == 1) && (counter < count)){//读取 write(out_file, &buff_unit, 1);//写入 counter ++;}close(in_file);close(out_file);return 0;
}int custom(int need){int fd;customing(fifo_file, need);//取if((fd = open(fifo_file, O_RDWR)) < 0){//读写方式打开 perror("FunctI/On myfilecopy error in source_file");return  -1;}lock_set(fd, F_WRLCK);//上锁,写入锁 myfilecopy(fifo_file, temp_file, need, MAX_FILE_SIZE, 0);//将第一个文件内容复制到另一个文件,偏移>myfilecopy(temp_file, fifo_file, 0, MAX_FILE_SIZE, 0);lock_set(fd, F_UNLCK);//解锁 unlink(temp_file);//删除 close(fd);return 0;}int main(int argc, const char *argv[]){int customer_capacity = 0;if(argc > 1){sscanf(argv[1], "%d", &customer_capacity);//消费数目写入 }if(customer_capacity > 0){custom(customer_capacity);}return 0;}

流程:
在这里插入图片描述

这里对open函数进行再次扩充讲解:

当文件被一个进程植入写入锁的时候,另一个进程仍可以通过open函数获取该文件的标志位,但却不能进行read或write函数操作,因为会受到写入锁的阻止

朴素的将写入锁是阻止其他进程对文件的读写操作,而不是open操作

在这里插入图片描述
之前一直不理解为什么customing函数中下列语句不会报错,通过用printf函数取点才发现问题

if((fd = open(myfifo, O_RDONLY)) < 0){//只读 perror("FunctI/On customing error");return -1;
}

看来看课本和懂课本是天差地别的

还有一点注意的是:

生产者代码中的:

while(time_life --){if(product() < 0){break;} sleep(time_step);
}

其中:

sleep(time_step);

这个延时语句作用巨大:

lock_set(fd, F_WRLCK);//上锁,写入锁 
myfilecopy(fifo_file, temp_file, need, MAX_FILE_SIZE, 0);//将第一个文件内容复制到另一个文件,偏移>
myfilecopy(temp_file, fifo_file, 0, MAX_FILE_SIZE, 0);
lock_set(fd, F_UNLCK);//解锁

其作用是为了让消费者中这个文件挪动语句能有时间完成
同时也用于读取生产出来的字符:

while((read(in_file, &buff_unit, 1) == 1) && (counter < count)){//读取 write(out_file, &buff_unit, 1);//写入 counter ++;}

上述语句在字符未被生产,或者文件被锁住,会一直等待,直到解锁或者有字符被生产

例如文件中生产abc,消费a,所以挪位后为bc

效果:

已生产五个字符:
在这里插入图片描述

消费四个:
在这里插入图片描述

最后剩一个:

在这里插入图片描述

同时进行如下:

在这里插入图片描述
整个文件被锁住,只出现在生产者将生产的字符写入文件和文件挪动这俩操作

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/176093.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ElasticSearch(ES)8.1及Kibana在docker环境下如何安装

ES基本信息介绍 Elasticsearch&#xff08;简称ES&#xff09;是一个开源的分布式搜索和分析引擎&#xff0c;最初由Elastic公司创建。它属于Elastic Stack&#xff08;ELK Stack&#xff09;的核心组件之一&#xff0c;用于实时地存储、检索和分析大量数据。 以下是Elastics…

云起无垠典型案例入选《2023软件供应链安全洞察》报告

近日&#xff0c;历时6个月&#xff0c;由ISC编制的《2023软件供应链安全洞察》报告&#xff08;以下简称《报告》&#xff09;正式对外发布。《报告》围绕软件供应链安全现状、技术内核、治理指南、落地实践展开&#xff0c;以期为行业从业者提供有价值的信息和洞见&#xff0…

GoLong的学习之路(十六)基础工具之Gin框架

Gin框架介绍及使用&#xff0c;这张不用看内容就知道非常重要&#xff0c;重要到什么地步呢&#xff1f;重要到开发java不会Spring全家桶这种概念。 上几篇文章写的是如何构建骨架&#xff0c;经脉。这一章是将血肉注入。 文章目录 Gin框架RESTful API Gin渲染HTML渲染静态文件…

【mfc/VS2022】计图实验:绘图工具设计知识笔记3

实现类对串行化的支持 如果要用CArchive类保存对象的话&#xff0c;那么这个对象的类必须支持串行化。一个可串行化的类通常有一个Serialize成员函数。要想使一个类可串行化&#xff0c;要经历以下5个步骤&#xff1a; 1、从CObject派生类 2、重写Serialize成员函数 3、使用DE…

PostGreSQL:数据表继承

PostGreSQL手册的简史部分介绍到&#xff1a;被称为PostGreSQL的对象关系型数据库管理系统&#xff0c;由美国加州大学伯克利 分校编写的POSTGRES软件包发展而来。经过十几年的发展&#xff0c;PostGreSQL目前是世界上最先进的开源数据库。 The object-relational database man…

【C++】string类

STL STL(standard template libaray-标准模板库)&#xff1a;是C标准库的重要组成部分&#xff0c;不仅是一个可复用的组件库&#xff0c;而且是一个包罗数据结构与算法的软件框架。 为什么学习string类&#xff1f; 1、C语言中的字符串 C语言中&#xff0c;字符串是以\0结尾…

计组之存储系统

存储器概述 分类 1.按在计算机中的作用&#xff08;层次&#xff09;分类 主存储器。CPU可以直接随机地对其进行访问&#xff0c;也可以和高速缓冲存储器&#xff08;Cache)及辅助存储器交换数据。辅助存储器。辅存的内容需要调入主存后才能被CPU访问。高速缓冲存储器。位于…

SSM咖啡点餐管理系统开发mysql数据库web结构java编程计算机网页源码eclipse项目

一、源码特点 SSM 咖啡点餐管理系统是一套完善的信息系统&#xff0c;结合SSM框架完成本系统&#xff0c;对理解JSP java编程开发语言有帮助系统采用SSM框架&#xff08;MVC模式开发&#xff09;&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主 要采用B/S模式开…

Spring@Lazy是如何解决构造函数循环依赖问题

Spring实例化源码解析之循环依赖CircularReference这章的最后我们提了一个构造函数形成的循环依赖问题&#xff0c;本章就是讲解利用Lazy注解如何解决构造函数循环依赖和其原理。 准备工作 首先创建两个构造函数循环依赖的类&#xff0c;TestA和TestB&#xff0c;代码如下&am…

通用开源自动化测试框架 - Robot Framework

一、什么是 Robot Framework&#xff1f; 1. Robot Framework 的历史由来 Robot Framework是一种通用的自动化测试框架&#xff0c;最早由Pekka Klrck在2005年开发&#xff0c;并由Nokia Networks作为内部工具使用。后来&#xff0c;该项目以开源形式发布&#xff0c;并得到了…

Py之pypdf:pypdf的简介、安装、使用方法之详细攻略

Py之pypdf&#xff1a;pypdf的简介、安装、使用方法之详细攻略 目录 pypdf的简介 pypdf的安装 pypdf的使用方法 1、基础用法 pypdf的简介 pypdf是一个免费的、开源的纯python PDF库&#xff0c;能够拆分、合并、裁剪和转换PDF文件的页面。它还可以为PDF文件添加自定义数据…

喜讯!合合信息顺利通过CMMI3级评估

近日&#xff0c;在擎标顾问团的咨询辅导下&#xff0c;上海合合信息科技股份有限公司&#xff08;简称“合合信息”&#xff09;顺利通过了CMMI3级评估。CMMI是国际上最流行、最实用的一种软件生产过程标准和软件企业成熟度等级认证的标准&#xff0c;通过该认证表明企业在开发…

CS224W1.1——图机器学习介绍

文章目录 1. 介绍2. 主要问题3. 深度学习如何应用在图结构中4. 课程大纲 学习一下斯坦福CS224W的图机器学习&#xff08;2021年&#xff09;&#xff0c;并做一下学习笔记&#xff0c;主要是研究方向与图神经网络相关。这次是第一次笔记&#xff0c;图片很多都是从斯坦福的PPT里…

Flask基本教程以及Jinjia2模板引擎简介

flask基本使用 直接看代码吧&#xff0c;非常容易上手&#xff1a; # 创建flask应用 app Flask(__name__)# 路由 app.route("/index", methods[GET]) def index():return "FLASK&#xff1a;欢迎访问主页&#xff01;"if __name__ "__main__"…

Flask 路由机制分析之一

一、前言 《Flask Run运行机制剖析》这篇我们讲了应用启动的内部机制&#xff0c;启动后就开始监听Http请求了&#xff0c;请求过来如何跳到对应的函数执行&#xff0c;这就是路由机制。我们沿用上一篇例子&#xff0c;来探究一下app.route("/")内部干了些什么事。 …

VDA到Excel方案介绍之自定义邮件接收主题

VDA标准是德国汽车工业协会&#xff08;Verband der Automobilindustrie&#xff0c;简称VDA&#xff09;制定的一系列汽车行业标准。这些标准包括了汽车生产、质量管理、供应链管理、环境保护、安全性能等方面的规范和指南。VDA标准通常被德国和国际上的汽车制造商采用&#x…

【算法-数组1】二分查找 和 移除元素

今天&#xff0c;带来XXX的讲解。文中不足错漏之处望请斧正&#xff01; 理论基础 二分查找 给定一个 n 个元素有序的&#xff08;升序&#xff09;整型数组 nums 和一个目标值 target &#xff0c;写一个函数搜索 nums 中的 target&#xff0c;如果目标值存在返回下标&#…

yum 命令

基本语法 yum [选项] [参数] 选项说明 -y 对所有提问都回答“yes” 参数说明 实操 yum list | grep firefox yum -y remove firefox yum -y install firefox

使用MobaXterm向linux窗口化传输文件

使用MobaXterm向linux窗口化传输文件 之前上大学的时候&#xff0c;经常是XSheel配合Xftp使用&#xff0c;Xftp可以窗口化的往linux服务器传输文件&#xff0c;但是有一个问题&#xff0c;就是Xftp是收费的。 后来工作之后师兄给推荐了一个免费的&#xff0c;又好用的类似于Xf…

uni-app/vue 文字转语音朗读(附小程序语音识别和朗读)uniapp小程序使用文字转语音播报类似支付宝收款播报小程序语音识别和朗读)

uni-app/vue 文字转语音朗读&#xff08;小程序语音识别和朗读&#xff09; uniapp小程序功能集合 1、uniapp小程序文字转语音播报 一、第一种方式&#xff1a;直接加语音包 固定的文本 先利用工具生成了 文本语音mp3文件&#xff0c;放入项目中&#xff0c;直接用就好了 …