2015-08-29 3 views
4

Я создал FIFO, написал ему и отсоединил его. К моему удивлению, я смог прочитать данные из fifo после разговора, почему?Чтение из FIFO после unlink()

#include <fcntl.h> 
#include <sys/stat.h> 
#include <stdio.h> 
#include <stdlib.h> 
#include <unistd.h> 
#include <sys/wait.h> 

#define MAX_BUF 256 
int main() 
{ 
    int fd; 
    char * myfifo = "/tmp/myfifo"; 

    /* create the FIFO (named pipe) */ 
    mkfifo(myfifo, 0666); 

    int pid = fork(); 
    if (pid != 0) 
    { 
     /* write "Hi" to the FIFO */ 
     fd = open(myfifo, O_WRONLY); 
     write(fd, "Hi", sizeof("Hi")); 
     close(fd); 

     /* remove the FIFO */ 
     unlink(myfifo); 
    } 
    else 
    { 
     wait(NULL); 
     char buf[MAX_BUF]; 

     /* open, read, and display the message from the FIFO */ 
     fd = open(myfifo, O_RDONLY); 
     read(fd, buf, MAX_BUF); 
     printf("Received: %s\n", buf); 
     close(fd); 

     return 0; 
    } 


    return 0; 
} 
+1

Это нормальное поведение в Unix. Нежелательный контент сохраняется до тех пор, пока по меньшей мере один процесс имеет по меньшей мере один файловый дескриптор, который через ядро, связанное с указанным несогласованным контентом. Это не относится к FIFO. Он работает со всеми типами файлов. – PSkocik

+0

Каков правильный способ его использования? Когда я должен использовать вызов unlink? –

+0

Это прекрасно, если вы отключаете файл сразу после его открытия. На самом деле я думаю, что это лучше, чем unliking по имени at_exit, потому что имя является своего рода слабой ссылкой на фактический файл (кто-то мог заменить файл во время вашей программы, и теперь ваша программа могла бы удалить что-то еще, чем файл, который он открыл).Unlinking + обращение с filedescriptor, указывающее на несвязанный контент, - довольно стандартный способ делать вещи в Unix. – PSkocik

ответ

1

Если вы не передать O_NONBLOCK флаг open(2), открыв блоки FIFO, пока другой конец не открыт. От man 7 fifo:

FIFO должен быть открыт на обоих концах (чтение и запись), прежде чем данные могут быть переданы. Обычно открываются блоки FIFO, пока не открывается другой конец .

Процесс может открыть FIFO в неблокирующем режиме. В этом случае открытие для чтения будет успешным, даже если никто не открыл на стороне записи , но открытие только для записи не будет выполнено с помощью ENXIO (нет такого устройства или адреса ), если другой конец уже не открыт.

Скажем, ваши родительские/дочерние процессы неявно синхронизируются при открытии FIFO. Поэтому к моменту, когда родительский процесс вызывает unlink(2), дочерний процесс давно открыл FIFO. Таким образом, ребенок будет всегда найти объект FIFO и открыть его до того, как родительский вызовет unlink(2).

Примечание: unlink(2): unlink(2) просто удаляет имя файла из файловой системы; пока существует хотя бы один процесс с открытием файла (FIFO в этом случае), базовый объект будет сохраняться. Только после того, как этот процесс завершится или завершится, файловый дескриптор освободит операционную систему от связанных ресурсов. FWIW, это не имеет отношения к сфере этого вопроса, но, похоже, стоит отметить.

Несколько других (несвязанных) замечания:

  • Не называйте wait(2) на ребенка. Он вернет ошибку (которую вы незамедлительно проигнорируете), потому что ребенок не разблокировал какой-либо процесс.
  • mkfifo(3), fork(2), open(2), read(2), write(2), close(2) и unlink(2) все может потерпеть неудачу и вернуть -1. Вы должны изящно обрабатывать возможные ошибки, а не игнорировать их. Общей стратегией для этих игрушечных программ является печать описательного сообщения об ошибке с perror(3) и завершение.
  • Если вы просто хотите, чтобы связь с родителем была дочерней, используйте трубку: ее проще настроить, вам не нужно ее отключать, и она не отображается в файловой системе (но вам нужно создать ее с помощью pipe(2) перед форсированием, так что ребенок может получить к нему доступ).