Почему моя программа зависает при открытии канала mkfifo-ed?

Я использую mkfifo для создания именованного канала. Затем я использую следующую программу, чтобы открыть его. Однако программа зависает на строчке fopen. Здесь что-то не так?

int main(int argc, char** argv) {
char* line = "hello, world!";
FILE* fp = fopen("/tmp/myFIFO", "rw");
fprintf(fp, line);
fclose(fp);
return 0;
}

person flyingbin    schedule 14.12.2011    source источник


Ответы (2)


Попробуйте передать "w" в качестве режима для открытия. "rw" не является допустимым аргументом режима для fopen, и даже если бы это было так, вы, вероятно, не захотите одновременно читать и записывать в FIFO в одном процессе (хотя это возможно, см. Ниже).

В качестве аргумента правильный режим для открытия файла как для чтения, так и для записи - "r+" или "w+" (см. ответы на этот вопрос о различиях).

Эта программа правильно запишет в FIFO:

#include <stdio.h>
int main(int argc, char** argv) {
    FILE* fp = fopen("/tmp/myFIFO", "w");
    fprintf(fp, "Hello, world!\n");
    fclose(fp);
    return 0;
}

Обратите внимание, что fopen в приведенной выше программе будет блокироваться до тех пор, пока FIFO не будет открыт для чтения. Когда он блокируется, запустите это в другом терминале:

$ cat /tmp/myFIFO
Hello, world!
$ 

Причина блокировки в том, что fopen не передает O_NONBLOCK в open:

$ strace -P /tmp/myFIFO ./a.out
open("/tmp/myFIFO", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 3
...

Некоторая предыстория открытия FIFO

Только для чтения, без блоков O_NONBLOCK: open, пока другой процесс не откроет FIFO для записи. Это поведение при использовании fopen с аргументом режима "r".

Только запись, без блоков O_NONBLOCK: open, пока другой процесс не откроет FIFO для чтения. Это поведение при использовании fopen с аргументом режима "w".

Только для чтения, O_NONBLOCK: open немедленно возвращается.

Только для записи с O_NONBLOCK: open возвращает ошибку с errno, установленным в ENXIO, если другой процесс не открыл FIFO для чтения.

Информация из "Расширенного программирования в среде UNIX" У. Ричарда Стивенса.

Открытие FIFO для чтения и записи

Открытие FIFO для чтения и записи в рамках одного процесса также возможно в Linux. На справочной странице Linux FIFO говорится:

В Linux открытие FIFO для чтения и записи будет успешным как в блокирующем, так и в неблокирующем режиме. POSIX оставляет такое поведение неопределенным. Это можно использовать, чтобы открыть FIFO для записи, пока нет доступных читателей. Процесс, который использует оба конца соединения для взаимодействия с самим собой, должен быть очень осторожен, чтобы избежать взаимоблокировок.

Вот программа, которая записывает и читает из одного и того же FIFO:

#include <stdio.h>
int main(int argc, const char *argv[]) {
    char buf[100] = {0};
    FILE* fp = fopen("/tmp/myFIFO", "r+");
    fprintf(fp, "Hello, world!\n");
    fgets(buf, sizeof(buf), fp);
    printf("%s", buf);
    fclose(fp);
    return 0;
}

Он не блокируется и сразу возвращается:

$ gcc fifo.c && ./a.out 
Hello, world!

Обратите внимание, что это не переносимо и может не работать в операционных системах, кроме Linux.

person Tim    schedule 24.07.2012

Процесс блокируется до тех пор, пока не откроется другой конец трубы.

person NPE    schedule 14.12.2011