当前位置: 首页 > news >正文

【进程与线程】Linux文件 I/O 编程中的生产者与消费者案例

生产者与消费者问题是经典的多线程同步问题,通常用于描述两个进程之间共享资源的协作。在 Linux 文件 I/O 中,我们这里使用有名管道(FIFO) 来实现生产者与消费者模型。

有名管道是一个特殊的文件,可以在两个不相关的进程之间传递数据(非亲缘进程)。它的特点是:

  1. 数据以先进先出的顺序传递。
  2. 数据在被读取后从管道中移除。
实现步骤
  1. 创建有名管道:使用 mkfifo() 创建一个有名管道文件。
  2. 生产者进程:打开有名管道并向其中写入数据。
  3. 消费者进程:打开有名管道并从其中读取数据。
  4. 同步与阻塞:
    • 有名管道是阻塞的:
      • 如果生产者没有写入数据,消费者会阻塞等待。
      • 如果消费者没有读取数据,生产者会阻塞等待。
代码实现

C语言实现,分为生产者和消费者两个独立的进程:

头文件与常量

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <errno.h>

#define FIFO_FILE "myfifo" // 定义有名管道的文件名
#define BUFFER_SIZE 256    // 定义缓冲区大小

生产者程序
生产者负责生成数据并写入管道。

void producer() {
    int fd;
    char buffer[BUFFER_SIZE];
    int count = 0;

    // 打开有名管道(写入模式)
    fd = open(FIFO_FILE, O_WRONLY);
    if (fd == -1) {
        perror("Producer: Failed to open FIFO");
        exit(EXIT_FAILURE);
    }

    printf("Producer: Writing to FIFO...\n");

    // 模拟生产数据
    while (1) {
        snprintf(buffer, BUFFER_SIZE, "Message %d", count);
        write(fd, buffer, strlen(buffer) + 1); // 写入数据到管道
        printf("Producer: Sent '%s'\n", buffer);

        count++;
        sleep(1); // 模拟生产数据所需的时间
    }

    close(fd); // 关闭管道
}

消费者程序
消费者负责从管道中读取数据。

void consumer() {
    int fd;
    char buffer[BUFFER_SIZE];

    // 打开有名管道(读取模式)
    fd = open(FIFO_FILE, O_RDONLY);
    if (fd == -1) {
        perror("Consumer: Failed to open FIFO");
        exit(EXIT_FAILURE);
    }

    printf("Consumer: Reading from FIFO...\n");

    // 模拟消费数据
    while (1) {
        memset(buffer, 0, BUFFER_SIZE);   // 清空缓冲区
        int bytes = read(fd, buffer, BUFFER_SIZE); // 从管道中读取数据

        if (bytes > 0) {
            printf("Consumer: Received '%s'\n", buffer);
        } else if (bytes == 0) {
            // 管道写入端关闭时,read 返回 0
            printf("Consumer: No more data to read. Exiting...\n");
            break;
        } else {
            perror("Consumer: Read error");
            exit(EXIT_FAILURE);
        }
    }

    close(fd); // 关闭管道
}

主程序

主程序创建管道并选择运行生产者或消费者。

int main(int argc, char *argv[]) {
    // 创建有名管道
    if (mkfifo(FIFO_FILE, 0666) == -1) {
        if (errno != EEXIST) {
            perror("Failed to create FIFO");
            exit(EXIT_FAILURE);
        }
    }

    if (argc < 2) {
        fprintf(stderr, "Usage: %s producer|consumer\n", argv[0]);
        exit(EXIT_FAILURE);
    }

    if (strcmp(argv[1], "producer") == 0) {
        producer(); // 启动生产者
    } else if (strcmp(argv[1], "consumer") == 0) {
        consumer(); // 启动消费者
    } else {
        fprintf(stderr, "Invalid argument. Use 'producer' or 'consumer'.\n");
        exit(EXIT_FAILURE);
    }

    return 0;
}

运行步骤:

  1. 编译程序:
gcc -o fifo_example fifo_example.c
  1. 运行消费者:
    • 在一个终端中启动消费者:
./fifo_example consumer
  1. 运行生产者:
./fifo_example producer
  1. 观察输出:
    • 消费者终端将实时显示从管道中读取的数据。
    • 生产者终端会显示发送的数据。

示例输出

生产者终端:

Producer: Writing to FIFO...
Producer: Sent 'Message 0'
Producer: Sent 'Message 1'
Producer: Sent 'Message 2'
...

消费者终端:

Consumer: Reading from FIFO...
Consumer: Received 'Message 0'
Consumer: Received 'Message 1'
Consumer: Received 'Message 2'
...

注意事项:

  1. 管道阻塞:
    • 如果生产者启动后没有消费者读取,生产者会阻塞,直到消费者启动并读取数据。
    • 同样,如果消费者启动后没有生产者写入,消费者会阻塞,直到生产者写入数据。
  2. 管道的清理:
    • 运行结束后,删除管道文件:
rm myfifo
  1. 并发问题:
    • 这个示例中只有一个生产者和一个消费者。如果需要支持多个生产者和消费者,可以使用信号量或文件锁机制进行同步。

这篇文章通过生产者和消费者模型展示了使用有名管道传递数据的基本方法。有点在于易于实现,适合简单的进程间通信;缺点是仅支持单向通信。阻塞模式需要注意处理多个进程的同步问题。

以上。仅供学习与分享交流,请勿用于商业用途!转载需提前说明。

我是一个十分热爱技术的程序员,希望这篇文章能够对您有帮助,也希望认识更多热爱程序开发的小伙伴。
感谢!

相关文章:

  • 图解循环神经网络(RNN)
  • 基于Ubuntu系统的docker环境对MySQL8.0.36主从部署
  • 智能停车收费-------如何用stm32G431结合LCD的uC8230型液晶控制器的驱动程序显示动态二维码
  • eNSP防火墙综合实验
  • PH热榜 | 2025-02-18
  • Linux下为Intel核显安装OpenCL
  • C++基础知识学习记录—string类
  • 什么是Embedding、RAG、Function calling、Prompt engineering、Langchain、向量数据库? 怎么使用
  • Linux3-文件io、时间有关函数
  • 使用API有效率地管理Dynadot域名,参与过期域名竞价
  • 高子昂医编---23岁,医疗编上岸,正式开启养老生活
  • 【Go | 从0实现简单分布式缓存】-2:HTTP服务端与一致性哈希
  • 【Spring+MyBatis】_图书管理系统(中篇)
  • 禁止WPS强制打开PDF文件
  • linux环境-nginx通过nginx_upstream_check_module模块,配置服务自动检测-日志自动分割
  • 【Spring详解二】容器的基本实现
  • 制造运营管理(MOM)与仓库管理系统(WMS)何以相辅相成对企业的生产管理进行提升
  • ​实在智能与宇树科技、云深科技一同获评浙江省“人工智能服务商”、 “数智优品”​等荣誉
  • uniapp 连接mqtt
  • JAXB复杂对象反序列化
  • “注胶肉”或已泛滥?这几种肉,再爱吃也要管住嘴
  • 媒体:不能让追求升学率,成为高中不双休的借口
  • 100%关税!特朗普要让美国电影100%美国制造
  • 龚正盛秋平王晓真共同启动2025国际消费季暨第六届上海“五五购物节”
  • 周劼已任中国航天科技集团有限公司董事、总经理、党组副书记
  • 国务院食安办:加强五一假期食品生产、销售、餐饮服务环节监管