Почему мои записи не блокируются в этот канал? - PullRequest
0 голосов
/ 07 июня 2018

Я пишу небольшую тестовую программу для Linux fifo.

Я создал канал, используя mkfifo mpipe.Программа должна выполнить одну запись на каждый переданный ей аргумент.Если никакие аргументы не отправляются, то он выполняет одно чтение из канала.

Вот мой код

int main(int argc, char *argv[])
{
    if (argc > 1)
    {
       int fd = open("./mpipe", O_WRONLY);
       int i = 1;
       for (i; i < argc; i++)
       {
           int bytes = write(fd, argv[i], strlen(argv[i]) + 1);
           if (bytes <= 0)
           {
               printf("ERROR: write\n");
               close(fd);
               return 1;
           }
           printf("Wrote %d bytes: %s\n", bytes, argv[i]);
       }

       close(fd);
       return 0;
    }

    /* Else perform one read */
    char buf[64];
    int bytes = 0;

    int fd = open("./mpipe", O_RDONLY);
    bytes = read(fd, buf, 64);
    if (bytes <= 0)
    {
        printf("ERROR: read\n");
        close(fd);
        return 1;
    }
    else
    {
        printf("Read %d bytes: %s\n", bytes, buf);
    }

    close(fd);
    return 0;
}

Я бы ожидал, что поведение будет примерно таким ...

Я звоню ./pt hello i am the deepest guy, и я ожидаю, что он заблокирует 6 чтений.Вместо этого одного чтения достаточно для запуска нескольких записей.Мой вывод выглядит как

# Term 1 - writer
$: ./pt hello i am the deepest guy # this call blocks until a read, but then cascades.
Just wrote hello
Just wrote i
Just wrote am
Just wrote the # output ends here

# Term 2 - reader
$: ./pt
Read 6 bytes: hello

Может ли кто-нибудь помочь объяснить это странное поведение?Я думал, что каждое чтение должно совпадать с записью в отношении связи по каналу.

1 Ответ

0 голосов
/ 08 июня 2018

Здесь происходит то, что ядро ​​блокирует процесс записи в системном вызове open(2), пока читатель не откроет его для чтения.(Для работы fifo требуется, чтобы оба конца были подключены к процессам). Как только читатель делает первый вызов read(2) (либо блок записи, либо блок чтения, который первым получает системный вызов) Ядро передает все данные от модуля записи кчитатель, и пробуждает оба процесса (это причина получения только первого параметра командной строки, а не первых 16 байтов от пишущего устройства, вы получаете только шесть символов {'h', 'e', 'l', 'l', 'o', '\0' } от блокирующего писателя)

Наконецпоскольку читатель просто закрывает fifo, писатель погибает с сигналом SIGPIPE, поскольку читатели больше не открывают fifo.Если вы установите обработчик сигнала в процессе записи (или проигнорируете сигнал), вы получите сообщение об ошибке из системного вызова write(2), сообщающее, что больше нет читателей, заблокированных на fifo (значение EPIPE errno) при блокировкеwrite.

Просто обратите внимание, что это функция, а не ошибка, способ узнать, что записи не будут доступны любому читателю, пока вы не закроете и снова не откроете fifo.

Ядро блокируетInode для fifo для всех вызовов read(2) или write(2), поэтому даже другой процесс, выполняющий еще один write(2) на fifo, будет заблокирован, и вы не получите данные о считывателе от этого второго автора (если выИмеется).Вы можете попробовать, если хотите, запустить двух авторов и посмотреть, что произойдет.

$ pru I am the best &
[1] 271
$ pru
Read 2 bytes: I
Wrote 2 bytes: I
Wrote 3 bytes: am
[1]+  Broken pipe             pru I am the best  <<< this is the kill to the writer process, announced by the shell.
$ _
...