Как определить, какая часть моего кода генерирует фатальную ошибку: glibc обнаружил недопустимую ошибку дескриптора stdio?

Я пытаюсь написать простую программу для копирования файла в другой, используя 2 процесса. Я хочу использовать общую память, чтобы открыть оба файла и получить часть общей памяти размером 1 байт, которая будет использоваться в качестве памяти обмена взаимоисключающим образом.

Таким образом, основной процесс должен открыть оба файла и поместить их в общую память; fork дважды, я получаю 2 процесса A и B. Процесс A должен прочитать 1 байт первого файла, поместить его в общую память обмена и разблокировать мьютекс для процесса B. Процесс B должен скопировать файл из общей памяти обмена и поместить в своем файле и разблокировать мьютекс для процесса А. И так далее.

#define SIZE 4096

void reader_process(FILE* fptr,char*exch, sem_t*mut){
    while(1){
        sem_wait(mut);
        *exch = (char) getc(fptr);
        sem_post(mut+1);
    }
}

void writer_process(FILE* fptr,char*exch, sem_t*mut){
    if(*exch == EOF){
        printf("done\n");
        exit(0);
    }

    while(1){
        sem_wait(mut);
        putc((int)*exch,fptr);
        sem_post(mut-1);
    }
}

int main(int argc, char *argv[]){
    FILE* shared_f_ptr[2];
    pid_t pid;
    //2 files name.
    char *files[2];
    int fd[2];

    //open files.
    files[0] = argv[1];
    printf("%s\n",files[0]);
    FILE* fpointer1 = fopen(files[0],"r+");
    if (fpointer1 == NULL){
        perror("fopen\n");
        exit(-1);
    }
    fd[0] = fileno(fpointer1);

    files[1] = argv[2];
    printf("%s\n",files[1]);
    FILE* fpointer2 = fopen(files[1],"r+");
    if (fpointer2 == NULL){
        perror("fopen\n");
        exit(-1);
    }
    fd[1] = fileno(fpointer2);

    //shared File pointers.
    shared_f_ptr[0] = (FILE*)mmap(NULL, SIZE*sizeof(char),
       PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS,
       fd[0], 0);
    if (shared_f_ptr[0] == MAP_FAILED){
        perror("mmap\n");
        exit(-1);
    }

    shared_f_ptr[1] = (FILE*)mmap(NULL, SIZE*sizeof(char),
       PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS,
       fd[1], 0); 
    if (shared_f_ptr[1] == MAP_FAILED){
        perror("mmap\n");
        exit(-1);
    }
    //shared mem for 1B exchange.
    char *shared_exchange = (char*)mmap(NULL, sizeof(char),
    PROT_READ | PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS,
     -1, 0);
    if (shared_exchange == MAP_FAILED){
        perror("mmap\n");
        exit(-1);
    }

    //mutex.
    sem_t *mut = (sem_t*)mmap(NULL, 2*sizeof(sem_t),
        PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS,
        -1, 0);
    sem_init(&mut[0],1,0);
    sem_init(&mut[1],1,0);



    //fork.

    pid = fork();
    if (pid == 0) {
        reader_process(shared_f_ptr[0],
        shared_exchange, &mut[0]);
    }
    if (pid == -1){
        perror("fork\n");
        exit(-1);
    }

    else pid = fork();

    if (pid == 0) writer_process(shared_f_ptr[1],
        shared_exchange, &mut[1]);

    if (pid == -1){
        perror("fork\n");
        exit(-1);
    }

    else{
        sem_post(&mut[0]);
    }
}

Я не ожидаю ошибки, которую я получаю Fatal error: glibc detected an invalid stdio handle, но я действительно не знаю, как найти причину проблемы.


person zurg    schedule 18.07.2019    source источник
comment
Какой отладчик вы используете?   -  person Scott Hunter    schedule 18.07.2019
comment
Я пробовал Валгринд   -  person zurg    schedule 18.07.2019
comment
Mmap не следует использовать для размещения указателей FILE. Вместо этого используйте fopen. Как shared_f_ptr[0] = fpointer1.   -  person S.S. Anne    schedule 18.07.2019
comment
И не используйте файловые дескрипторы.   -  person S.S. Anne    schedule 18.07.2019
comment
@ JL2210 Почему в этом случае нельзя использовать mmap? что, если мне нужно, чтобы файл был разделен между процессами? (я знаю, что мне не нужно это прямо сейчас, но что, если)   -  person zurg    schedule 18.07.2019
comment
Мне всегда кажется забавным, что эти заголовки вопросов сокращают ошибку до Fatal error: glibc detected.   -  person S.S. Anne    schedule 18.07.2019
comment
@zurg Потому что ФАЙЛ работает не так. Это непрозрачная структура, которую нужно создать с помощью fopen.   -  person S.S. Anne    schedule 18.07.2019


Ответы (1)


Не делайте этого:

//shared File pointers.
shared_f_ptr[0] = (FILE*)mmap(NULL, SIZE*sizeof(char),
   PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS,
   fd[0], 0);
if (shared_f_ptr[0] == MAP_FAILED){
    perror("mmap\n");
    exit(-1);
}

shared_f_ptr[1] = (FILE*)mmap(NULL, SIZE*sizeof(char),
   PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS,
   fd[1], 0); 
if (shared_f_ptr[1] == MAP_FAILED){
    perror("mmap\n");
    exit(-1);
}

Используйте это вместо этого:

shared_f_ptr[0] = fpointer1;
shared_f_ptr[1] = fpointer2;

Не используйте файловые дескрипторы, лежащие в основе каждого файла FILE. Вместо этого просто используйте сам FILE.

Кроме того, вместо использования fpointer1 и fpointer2 просто используйте shared_f_ptr[0] и shared_f_ptr[1].

Это возможное определение структуры FILE:

typedef struct _IO_FILE
{
    int __fd;
    int __flags;
    int __unget;
    char *__buffer;
    struct {
        size_t __orig;
        size_t __size;
        size_t __written;
    } __bufsiz;
    fpos_t __fpos;
} FILE;

Как видите, это структура, а не просто плоский указатель.

person S.S. Anne    schedule 18.07.2019
comment
спасибо, но делая это таким образом, который, кстати, решает проблему, канал ввода-вывода к файлу не может быть разделен между процессами, я прав? - person zurg; 18.07.2019
comment
@zurg Я думаю, это не имеет значения, но ты должен проверить. - person S.S. Anne; 18.07.2019
comment
Во всяком случае, вы можете просто повторно открыть файл в каждом разветвленном процессе (но я не думаю, что это понадобится. - person S.S. Anne; 18.07.2019