xozzslip
@xozzslip

Как работают pipe в UNIX?

В man странице по каналам приведён вот такой пример использования каналов:
main(int argc, char *argv[])
       {
           int pipefd[2];
           pid_t cpid;
           char buf;

           if (argc != 2) {
               fprintf(stderr, "Usage: %s <string>\n", argv[0]);
               exit(EXIT_FAILURE);
           }

           if (pipe(pipefd) == -1) {
               perror("pipe");
               exit(EXIT_FAILURE);
           }

           cpid = fork();
           if (cpid == -1) {
               perror("fork");
               exit(EXIT_FAILURE);
           }

           if (cpid == 0) {    /* Child reads from pipe */
               close(pipefd[1]);          /* Close unused write end */

               while (read(pipefd[0], &buf, 1) > 0)
                   write(STDOUT_FILENO, &buf, 1);

               write(STDOUT_FILENO, "\n", 1);
               close(pipefd[0]);
               _exit(EXIT_SUCCESS);

           } else {            /* Parent writes argv[1] to pipe */
               close(pipefd[0]);          /* Close unused read end */
               write(pipefd[1], argv[1], strlen(argv[1]));
               close(pipefd[1]);          /* Reader will see EOF */
               wait(NULL);                /* Wait for child */
               exit(EXIT_SUCCESS);
           }
       }

Не могу понять, почему можно быть уверенным в том, что сначала родитель запишет что-то в канал, а только потом потомок попытается что-то считать. Не может ли произойти ситуации, в которой потомок попытается считать данные из канала до того, как там что-то появится?

И вообще, как сделать так, чтобы процесс просыпался только тогда, когда в канале есть, что прочитать? Чтобы он считывал всё, что есть и засыпал обратно? Как это работает на уровне ОС?
  • Вопрос задан
  • 4309 просмотров
Решения вопроса 1
Вы используете блокирующее чтение/запись, поэтому операция чтения будет ожидать, пока не появятся данные. На время блокировки процесс будет засыпать, дополнительно для этого ничего делать не надо. Если записывающий процесс будет писать достаточно большой объем данных и читающий процесс не будет успевать считывать данные - то будет переполнен буфер pipe'а, тогда блокирована будет операция записи и "спать" будет пишущий процесс.
Вот если вы хотите избежать блокировок, то необходимо переводить дескрипторы в неблокирущий режим и использовать select()/poll() или аналоги.

На уровне ОС pipe() это просто буфер памяти в который данные могут быть записаны и считаны через дискриптор.
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы