通过共享内存和管道的 IPC 给出分段错误:C 中的 11

Posted

技术标签:

【中文标题】通过共享内存和管道的 IPC 给出分段错误:C 中的 11【英文标题】:IPC through shared memory and pipe gives segmentation fault: 11 in C 【发布时间】:2020-02-15 17:49:48 【问题描述】:

我正在尝试在父进程和子进程之间共享文件。父级通过管道发送文件,子级将这些行写入共享内存,以便父级可以通过共享内存读取和打印文件。但是,我遇到了分段错误:11。此外,我做了类似下面的代码的事情,但那时我无法获得正确的内容,甚至每次调用都得到不同的结果。

我不确定增加指针部分。但是,最好多关注一下代码。

编辑:我将 char* 更正为 char[] 并且分段错误现在消失了。但是,每次运行我都会得到不同的结果,输出中会看到一些额外的字符。

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

#define SHM_NAME_1 "Child 1"

int main()

    pid_t pid;
    FILE *file;
    char *infile = "in.txt";

    pid = fork();

    if(pid < 0)
        fprintf(stderr, "Fork failed\n");
        return 1;
    

    if(pid > 0) // parent

        file = fopen(infile, "r");

        if(file == 0)
            fprintf(stderr, "File failed\n");
            return 1;
        
        // close read end of pipe
        mknod("FIFO", S_IFIFO | 0666, 0);
        int fd = open("FIFO", O_WRONLY);

        char str[300];
        while(fgets(str, sizeof(str), file) > 0)
        
            // write all lines of file
            write(fd, str, strlen(str));
        
        // close file and pipe
        close(fd);
        fclose(file);
        // wait for child to write to shared memory
        wait(NULL);

        // open shared segment
        int shm_first = shm_open(SHM_NAME_1, O_RDONLY, 0666);

        if (shm_first == -1) 
            fprintf(stderr, "Failed: Shared Memory 1");
            exit(-1);
        

        // create memory pointer
        void *ptr = mmap(0,4096, PROT_READ, MAP_SHARED, shm_first, 0);

        if (ptr == MAP_FAILED) 
            printf("Map failed 1\n");
            return -1;
        
        // print out result and unlibk shared segment
        fprintf(stdout, "Normal input: \n%s\n", ptr);
        shm_unlink(SHM_NAME_1);

     else  // child

        // create the shared segment for the first time
        int shm_child_1 = shm_open(SHM_NAME_1, O_CREAT | O_RDWR, 0666);

        // configure the size of the shared memory segment 
        ftruncate(shm_child_1,4096);
        // map the pointer to the segment
        void *ptr_child_1 = mmap(0,4096, PROT_READ | PROT_WRITE, MAP_SHARED, shm_child_1, 0);

        if (ptr_child_1 == MAP_FAILED) 
        
            printf("Map failed in first child\n");
            return -1;
        


        mknod("FIFO", S_IFIFO | 0666, 0);
        int fd = open("FIFO", O_RDONLY);

        int num;
        char s[300];
        while((num = read(fd, s, sizeof(s)))> 0)
             
            sprintf(ptr_child_1, "%s", s);
            ptr_child_1 += num;
        

        close(fd);
        exit(0);

    

    return 0;

【问题讨论】:

我认为 EOF 发生了一些事情 【参考方案1】:

快速观察。

在以下代码中,您有一个未初始化为指向任何内容的 char 指针。这会导致 fgets 将从file 读取的内容复制到内存中的某个任意位置。

    char *str;
    while(fgets(str, 100, file) > 0)

既然缓冲区问题解决了,下面的表达式中的大括号也有问题

    while((num = read(fd, s, sizeof(s)) > 0))

num 将是 1 或 0,而不是读取的字节数或 eof 的 0。这应该是

    while((num = read(fd, s, sizeof(s))) > 0)

一旦读取了字节数,就需要将缓冲区归零。因为您使用的是 sprintf,它期望 %s 的参数是一个以零结尾的字符串。

    while((num = read(fd, s, sizeof(s)))> 0)
    
        s[num] = '\0';  // Terminate the string to the number of bytes read
        sprintf(ptr_child_1, "%s", s);
        ptr_child_1 += num;
    

【讨论】:

是的,当我更改为 char 数组时,它可以工作。但是现在子进程只读取我文件的第一行,即使父进程写入了所有行。 嗯,我想我也想通了,但我不知道为什么我会在输出末尾得到额外的字符/ 顺便说一句。在客户端代码中读取 char *r 时遇到同样的问题。 哇,谢谢!我做了类似的事情,在父级的while循环结束时,我显式发送了eof。

以上是关于通过共享内存和管道的 IPC 给出分段错误:C 中的 11的主要内容,如果未能解决你的问题,请参考以下文章

使用共享内存时出现分段错误

IPC$ 命名管道

进程间通信IPC之--共享内存

在 C 中使用共享内存的 IPC

共享内存是最快的一种IPC方式

IPC linux中数组存储的分段错误