IPC через общую память и канал дает ошибку сегментации: 11 в C

Я пытаюсь поделиться файлом между родительским и дочерним процессами. Родитель отправляет файл через конвейер, а дочерний элемент записывает эти строки в общую память, чтобы родитель мог прочитать и распечатать файл через общую память. Однако я получаю ошибку сегментации: 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;
}

person HARUN SASMAZ    schedule 15.02.2020    source источник
comment
Я предполагаю, что что-то происходит с EOF   -  person HARUN SASMAZ    schedule 15.02.2020


Ответы (1)


Одно быстрое наблюдение.

В следующем коде у вас есть указатель char, который не инициализирован, чтобы указывать на что-либо. Это заставляет fgets копировать то, что он читает из file, в произвольное место в памяти.

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

Теперь, когда проблемы с буфером решены, также есть проблема с фигурными скобками в следующем выражении.

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

num будет 1 или 0, а не количество прочитанных байтов или 0 для eof. Это должно быть

    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;
    }
person Chris Taylor    schedule 15.02.2020
comment
Да, когда я перешел на массив символов, он работает. Но теперь дочерний процесс просто читает первую строку моего файла, хотя родитель записывает все строки. - person HARUN SASMAZ; 15.02.2020
comment
Хм, думаю, я тоже это понял, но я не знаю, почему я получаю лишние символы в конце вывода/ - person HARUN SASMAZ; 15.02.2020
comment
Кстати. у вас та же проблема с чтением в char *r в клиентском коде. - person Chris Taylor; 15.02.2020
comment
Вау спасибо! Я сделал что-то подобное, в конце цикла while в родительском я явно отправляю eof. - person HARUN SASMAZ; 16.02.2020