You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用fork与pipe实现FCFS队列的入队与查询执行分离?

解决方案:基于Fork和Pipe实现FCFS任务队列

问题根源

原代码的核心错误是fork后父子进程的内存空间相互独立,父进程向队列中添加的任务,子进程完全看不到,导致处理进程永远无法执行任务。必须通过管道(Pipe)实现父子进程间的任务传递,管道本身就具备FCFS的特性,无需额外维护队列结构。

修正后的代码

SERVER.C

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

#define BUFFER_SIZE 16

int main(int argc, char* argv[]) {
    // 创建管道,用于父子进程传递任务
    int pipe_fd[2];
    if (pipe(pipe_fd) == -1) {
        perror("pipe");
        return 1;
    }

    // 创建FIFO,用于接收客户端请求
    if (mkfifo("fifo", 0666) == -1) {
        perror("mkfifo");
        close(pipe_fd[0]);
        close(pipe_fd[1]);
        return 1;
    }

    int pid = fork();
    if (pid == -1) {
        perror("fork");
        close(pipe_fd[0]);
        close(pipe_fd[1]);
        unlink("fifo");
        return 1;
    }

    if (pid == 0) {
        // 子进程:处理任务(从管道读取并执行)
        close(pipe_fd[1]); // 关闭写端
        char task[BUFFER_SIZE];
        ssize_t bytes_read;

        while (1) {
            // 阻塞读取管道,有任务才处理
            bytes_read = read(pipe_fd[0], task, BUFFER_SIZE);
            if (bytes_read > 0) {
                printf("执行任务:%s\n", task);
                // 这里可以替换为实际的任务执行逻辑
            } else if (bytes_read == 0) {
                // 管道写端关闭,退出循环
                break;
            } else {
                perror("read pipe");
                break;
            }
        }

        close(pipe_fd[0]);
        _exit(0);
    } else {
        // 父进程:接收客户端请求,写入管道
        close(pipe_fd[0]); // 关闭读端
        int fd_fifo = open("fifo", O_RDONLY);
        if (fd_fifo == -1) {
            perror("open fifo");
            close(pipe_fd[1]);
            kill(pid, SIGTERM);
            unlink("fifo");
            return 1;
        }

        char buffer[BUFFER_SIZE];
        ssize_t bytes_read;

        while (1) {
            // 阻塞读取FIFO的客户端请求
            bytes_read = read(fd_fifo, buffer, BUFFER_SIZE);
            if (bytes_read > 0) {
                // 将请求写入管道,传递给子进程
                write(pipe_fd[1], buffer, bytes_read);
            } else if (bytes_read == 0) {
                // FIFO写端关闭,继续等待新客户端连接
                continue;
            } else {
                perror("read fifo");
                break;
            }
        }

        close(fd_fifo);
        close(pipe_fd[1]);
        unlink("fifo");
        wait(NULL);
    }

    return 0;
}

CLIENT.C

#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>

#define BUFFER_SIZE 16

int main(int argc, char* argv[]) {
    if (argc != 2 || strlen(argv[1]) >= BUFFER_SIZE - 1) {
        fprintf(stderr, "用法:%s <任务内容>(长度不超过15字符)\n", argv[0]);
        return 1;
    }

    int fd_fifo = open("fifo", O_WRONLY);
    if (fd_fifo == -1) {
        perror("连接服务器失败");
        return 1;
    }

    ssize_t bytes_written = write(fd_fifo, argv[1], strlen(argv[1]) + 1);
    if (bytes_written == -1) {
        perror("发送任务失败");
        close(fd_fifo);
        return 1;
    }

    printf("已发送任务:%s(写入字节数:%zd)\n", argv[1], bytes_written);
    close(fd_fifo);

    return 0;
}

关键说明

  1. 管道的核心作用:父进程将从FIFO接收到的客户端任务写入管道,子进程从管道阻塞读取,天然实现FCFS顺序处理,无需额外维护队列结构。
  2. 阻塞特性优化:read操作在管道/FIFO无数据时会自动阻塞,避免了原代码中空轮询的资源浪费。
  3. 资源清理:添加了管道、FIFO的关闭和删除操作,防止残留系统资源。
  4. 客户端优化:增加参数合法性检查,修复原代码中strdup后重复strcpy的冗余操作。

内容的提问来源于stack exchange,提问作者Leonardo Alves

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 06:05:01