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

这篇具有很好参考价值的文章主要介绍了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 ALPHABET

const 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());//获取当前进程的ID
			break;
		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;//26
			 break;
		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;
}

流程:
Linux 基本语句_9_C语言_生产者&消费者,linux,c语言,算法

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

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

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

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

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

运行效果:

FIFO.txt文件上次运行时残留有数据
Linux 基本语句_9_C语言_生产者&消费者,linux,c语言,算法

生产五个数据:
Linux 基本语句_9_C语言_生产者&消费者,linux,c语言,算法
文件之前生产信息被清除,取而代之的是新数据:

Linux 基本语句_9_C语言_生产者&消费者,linux,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 MAX_FILE_SIZE 100 * 1024 * 102
 
 
 const 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());//获取当前进程的ID
                    break;                                                                     
        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;
 }

流程:
Linux 基本语句_9_C语言_生产者&消费者,linux,c语言,算法

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

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

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

Linux 基本语句_9_C语言_生产者&消费者,linux,c语言,算法
之前一直不理解为什么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

效果:

已生产五个字符:
Linux 基本语句_9_C语言_生产者&消费者,linux,c语言,算法

消费四个:
Linux 基本语句_9_C语言_生产者&消费者,linux,c语言,算法

最后剩一个:

Linux 基本语句_9_C语言_生产者&消费者,linux,c语言,算法

同时进行如下:

Linux 基本语句_9_C语言_生产者&消费者,linux,c语言,算法
整个文件被锁住,只出现在生产者将生产的字符写入文件和文件挪动这俩操作文章来源地址https://www.toymoban.com/news/detail-725775.html

到了这里,关于Linux 基本语句_9_C语言_生产者&消费者的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • go语言中实现生产者-消费者模式有哪些方法呢

    本文将介绍在 Go 语言中实现生产者消费者模式的多种方法,并重点探讨了通道、条件变量的适用场景和优缺点。我们将深入讨论这些方法的特点,以帮助开发者根据应用程序需求选择最适合的方式。通过灵活运用 Go 语言提供的并发原语,我们能够实现高效、可靠的生产者消

    2024年02月05日
    浏览(33)
  • Linux——生产者消费者模型和信号量

    目录 ​​​​​​​ 基于BlockingQueue的生产者消费者模型 概念 条件变量的第二个参数的作用  锁的作用 生产者消费者模型的高效性 生产者而言,向blockqueue里面放置任务 消费者而言,从blockqueue里面拿取任务: 总结 完整代码(不含存储数据的线程) 完整代码(含存储线程)  信

    2024年02月07日
    浏览(40)
  • Linux操作系统实验:生产者和消费者问题

    “生产者消费者”问题是一个著名的同时性编程问题的集合。通过编写经典的”生产者消费者”问题的实验,读者可以进一步熟悉 Linux 中多线程编程,并且掌握用信号量处理线程间的同步互斥问题。 VMware Workstation Pro “生产者消费者”问题描述如下。 有一个有限缓冲区和两

    2024年02月06日
    浏览(58)
  • Linux安装Kafka,创建topic、生产者、消费者

    1.创建安装目录/usr/local/kafka mkdir /usr/local/kafka 2.进入安装包目录 cd /usr/local/kafka  3.下载安装包 wget https://downloads.apache.org/kafka/3.3.1/kafka_2.12-3.3.1.tgz 4.解压安装包 tar -zxvf kafka_2.12-3.3.1.tgz 5.进入cd kafka_2.12-3.3.1目录 cd kafka_2.12-3.3.1/ 6.修改zookeeper配置 cat ./config/zookeeper.properties | grep

    2023年04月17日
    浏览(50)
  • 【Linux】cp问题,生产者消费者问题代码实现

    生产者消费者模式就是通过一个容器 来解决生产者和消费者的强耦合问题 。生产者和消费者彼此之间不直接通讯,而通过阻塞队列来进行通讯,所以生产者生产完数据之后不用等待消费者处理,直接扔给阻塞队列,消费者不找生产者要数据,而是直接从阻塞队列里取,阻塞

    2024年02月04日
    浏览(36)
  • 【Linux】生产者消费者模型代码实现和信号量

    一定要先理解生产者消费者模型的原理~ 文章目录 一、生产者消费者模型实现代码 二、信号量 1.基于环形队列的生产者消费者模型 总结 下面我们实现基于阻塞队列的生产消费模型: 在多线程编程中阻塞队列 (Blocking Queue) 是一种常用于实现生产者和消费者模型的数据结构。其

    2024年02月11日
    浏览(40)
  • 【Linux】基于环形队列的生产者消费者模型的实现

    文章目录 前言 一、基于环形队列的生产者消费者模型的实现 上一篇文章我们讲了信号量的几个接口和基于环形队列的生产者消费者模型,下面我们就快速来实现。 首先我们创建三个文件,分别是makefile,RingQueue.hpp,以及main.cc。我们先简单搭建一下环形队列的框架: 首先我们

    2024年02月11日
    浏览(45)
  • 【linux】线程同步+基于BlockingQueue的生产者消费者模型

    喜欢的点赞,收藏,关注一下把! 在线程互斥写了一份抢票的代码,我们发现虽然加锁解决了抢到负数票的问题,但是一直都是一个线程在抢票,它错了吗,它没错但是不合理。那我们应该如何安全合理的抢票呢? 讲个小故事。 假设学校有一个VIP学霸自习室,这个自习室有

    2024年02月03日
    浏览(99)
  • 『Linux』第九讲:Linux多线程详解(四)_ 生产者消费者模型

    「前言」文章是关于Linux多线程方面的知识,上一篇是 Linux多线程详解(三),今天这篇是 Linux多线程详解(四),内容大致是生产消费者模型,讲解下面开始! 「归属专栏」Linux系统编程 「主页链接」个人主页 「笔者」枫叶先生(fy) 「枫叶先生有点文青病」「每篇一句」

    2024年02月07日
    浏览(44)
  • Kafka 之生产者与消费者基础知识:基本配置、拦截器、序列化、分区器

    kafaf集群地址列表:理论上写一个节点地址,就相当于绑定了整个kafka集群了,但是建议多写几个,如果只写一个,万一宕机就麻烦了 kafka消息的key和value要指定序列化方法 kafka对应的生产者id 使用java代码表示则为以下代码:  可使用 retries 参数 进行设置,同时要注意记住两

    2024年02月05日
    浏览(55)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包