MST

星途 面试题库

面试题:C语言中Linux命名管道文件操作的同步与错误处理

使用C语言编写一个程序,包含命名管道的创建、写端和读端。要求在写端发送一系列数字(例如1 - 100)到命名管道,读端接收这些数字并计算它们的总和。在这个过程中,需要处理可能出现的各种错误(如管道创建失败、读写失败等),并且要确保读写操作的同步性,避免数据丢失或混乱。
13.6万 热度难度
编程语言C

知识考点

AI 面试

面试题答案

一键面试
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <string.h>

#define FIFO_NAME "myfifo"
#define BUFFER_SIZE 1024

void error_handling(const char *msg) {
    perror(msg);
    exit(EXIT_FAILURE);
}

int main() {
    int fd, res;
    char buffer[BUFFER_SIZE];
    mode_t fifo_mode = S_IFIFO | 0666;

    // 创建命名管道
    if (mkfifo(FIFO_NAME, fifo_mode) == -1 && errno != EEXIST) {
        error_handling("mkfifo");
    }

    // 写端
    if (fork() == 0) {
        fd = open(FIFO_NAME, O_WRONLY);
        if (fd == -1) {
            error_handling("open for writing");
        }

        for (int i = 1; i <= 100; i++) {
            snprintf(buffer, sizeof(buffer), "%d", i);
            res = write(fd, buffer, strlen(buffer));
            if (res == -1) {
                error_handling("write");
            }
            // 发送换行符,以便读端按行读取
            res = write(fd, "\n", 1);
            if (res == -1) {
                error_handling("write newline");
            }
        }

        close(fd);
        exit(EXIT_SUCCESS);
    }
    // 读端
    else {
        fd = open(FIFO_NAME, O_RDONLY);
        if (fd == -1) {
            error_handling("open for reading");
        }

        int sum = 0;
        while (1) {
            res = read(fd, buffer, sizeof(buffer) - 1);
            if (res <= 0) {
                if (res == 0) {
                    break;
                } else {
                    error_handling("read");
                }
            }
            buffer[res] = '\0';
            int num;
            sscanf(buffer, "%d", &num);
            sum += num;
        }

        close(fd);
        printf("Sum of numbers from 1 to 100 is: %d\n", sum);
        // 删除命名管道
        if (unlink(FIFO_NAME) == -1) {
            error_handling("unlink");
        }
    }

    return 0;
}
  1. 命名管道创建:使用mkfifo函数创建命名管道,如果管道已存在,忽略该错误(errno != EEXIST)。
  2. 写端操作
    • 使用fork创建子进程作为写端。
    • 使用open以只写模式打开命名管道。
    • 使用snprintf将数字转换为字符串,通过write写入管道,并在每个数字后写入换行符,以便读端按行读取。
  3. 读端操作
    • 父进程作为读端,使用open以只读模式打开命名管道。
    • 使用read按行读取管道中的数据,使用sscanf将读取的字符串转换为数字并累加到sum中。
  4. 错误处理
    • 对于mkfifoopenwritereadunlink等可能出错的函数,通过自定义的error_handling函数进行错误处理,打印错误信息并退出程序。
  5. 同步性
    • 通过按行写入和读取数据,确保了读写操作的同步性,避免数据丢失或混乱。并且父进程等待子进程写完数据后(子进程关闭写端后,读端read返回0),读端才会结束读取操作。