Linux Pipes как вход и выход - PullRequest
3 голосов
/ 14 ноября 2009

Я бы хотел сделать следующее внутри программы на C на Linux OS:

  • Создание ТРУБЫ с помощью системного вызова (или 2)
  • Выполнить новый процесс, используя exec ()
  • Подключите STDIN процесса к ранее созданному каналу.
  • Подключите выход процесса к другой ТРУБЕ.

Идея состоит в том, чтобы обойти любой доступ к диску для повышения производительности.

Я знаю, что создание каналов довольно просто с помощью системного вызова PIPE. и что я мог бы просто использовать popen для создания канала для ввода или вывода.

Но как бы вы поступили так для ввода и вывода?

Ответы [ 3 ]

7 голосов
/ 14 ноября 2009

С сантехникой нужно быть очень осторожным:

  1. Вызовите pipe () дважды, один для канала «потомок», другой для «канал от потомка», получая 4 файловых дескриптора.
  2. Вызовите fork ().
  3. у ребенка:
    • Вызовите close () для стандартного ввода (дескриптор файла 0).
    • Вызовите dup () - или dup2 () - чтобы преобразовать конец канала «потомок» в стандартный ввод.
    • Вызовите close () в конце чтения канала для потомка.
    • Вызовите close () в конце записи канала для потомка.
    • Вызовите close () для стандартного вывода (дескриптор файла 1).
    • Вызовите dup () - или dup2 () - чтобы сделать конец записи канала-потомка в стандартный вывод
    • Вызовите close () для конца записи канала от ребенка.
    • Вызовите close () для конца чтения канала от ребенка.
    • Выполнить требуемую программу.
  4. у родителей:
    • Вызовите close в конце чтения канала для потомка.
    • Вызовите close в конце записи для pipe-of-child.
    • Цикл отправки данных дочернему элементу в конце записи pipe-to-child и чтение данных от дочернего элемента в конце read of pipe-to-child
    • Если больше нет необходимости отправлять дочернему элементу, закройте конец записи "pipe-to-child".
    • Когда все данные будут получены, закройте конец чтения канала «от ребенка».

Обратите внимание, сколько закрытий, особенно у ребенка. Если вы используете dup2 (), вам не нужно явно закрывать стандартный ввод и вывод; однако dup () работает правильно, если вы делаете явное закрытие. Также обратите внимание, что ни dup (), ни dup2 () не закрывают файловый дескриптор, который дублируется. Если вы пропустите закрытие каналов, то ни одна из программ не сможет правильно определить EOF; тот факт, что текущий процесс все еще может записывать в канал, означает, что в канале нет EOF, и программа будет зависать бесконечно.

Обратите внимание, что это решение не изменяет стандартную ошибку для ребенка; он идет в то же место, что и стандартная ошибка для родителя. Часто это правильно. Если у вас есть конкретное требование, чтобы сообщения об ошибках от ребенка обрабатывались по-другому, то примите соответствующие меры и к стандартной ошибке ребенка.

1 голос
/ 14 ноября 2009

В зависимости от ваших потребностей, вам может оказаться проще просто использовать mkfifo (1), чтобы создать именованный канал, и ваши процессы читают / записывают в этот файл. Хотя имя файла указано в файловой системе, накладные расходы на использование анонимного канала не должны быть заметными.

0 голосов
/ 14 ноября 2009

Самым простым способом, вероятно, является выполнение /bin/sh, так что вы можете использовать знакомый синтаксис оболочки для указания каналов и разгрузить все сложности.

Что-то вроде:

execlp("sh", "-c", "cat /dev/zero | cat > /dev/null", NULL);
...