Передача по каналу как межпроцессное взаимодействие

Кажется, что следующее делает работу. Не совсем уверен, если какие-либо последствия для производительности хотя

9
задан unwind 14 December 2008 в 22:36
поделиться

3 ответа

Ничего себе, это - много вопросов. Давайте посмотрим, могу ли я покрыть все...

Кажется, что принимающий конец заблокирует ожидание входа, который я ожидал бы

Вы ожидаете правильно, что фактический вызов 'чтения' заблокируется, пока что-то не будет там. Однако я полагаю, что существуют некоторые функции C, которые позволят Вам 'посмотреть' на то, что (и сколько) ожидает в канале. К сожалению, я не помню, блокируется ли это также.

будет блок передающего конца, иногда ожидая кого-то для чтения из потока

Нет, отправка никогда не должна блокироваться. Думайте о разветвлениях, если это было каналом по сети к другому компьютеру. Вы хотели бы ожидать (через возможно высокую задержку), чтобы другой компьютер ответил, что это получило его? Теперь это - другой случай, если дескриптор читателя места назначения был закрыт. В этом случае у Вас должна быть некоторая проверка ошибок для обработки этого.

Если я пишу, что eof к потоку может я оставаться продолжить писать в тот поток, пока я не закрываю его

Я думал бы, что это зависит, на каком языке Вы используете и его реализация каналов. В C я сказал бы "нет". В оболочке Linux я сказал бы да. Кто-то еще с большим опытом должен был бы ответить на это.

Есть ли различия в названном поведении и каналы без имени? Насколько я знаю, да. Однако у меня нет большого опыта с именованным по сравнению с без имени. Я полагаю, что различие:

  • Единственное направление по сравнению с Двунаправленной связью
  • Чтение И запись в "в" и потоки потока

Это имеет значение, какой конец канала я открываю сначала с именованными каналами?

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

Действительно ли поведение каналов последовательно между различными системами Linux?

Снова, это зависит от какой язык, но обычно да. Когда-нибудь услышанный о POSIX? Это - стандарт (по крайней мере, для Linux, Windows делает свою собственную вещь).

Поведение каналов зависят от оболочки, которую я использую или способ, которым я настроил его?

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

Есть ли любые другие вопросы, которые я должен задавать

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

4
ответ дан 3 November 2019 в 00:05
поделиться

Это - все на основе подобной UNIX системы; я не знаком с определенным поведением последних версий Windows.

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

Да, хотя на современной машине этого не может часто происходить. Канал имеет промежуточный буфер, который может потенциально заполниться. Если это сделает, то сторона записи канала действительно заблокируется. Но если Вы думаете об этом, нет большого количества файлов, которые являются достаточно большими для риска этим.

Если я пишу, что eof к потоку может я оставаться продолжить писать в тот поток, пока я не закрываю его?

Гм, Вы имеете в виду как CTRL-D, 0x04? Несомненно, пока поток создан тот путь. То есть.

506 # cat | od -c
abc
^D
efg
0000000    a   b   c  \n 004  \n   e   f   g  \n                        
0000012

Есть ли различия в названном поведении и каналы без имени?

Да, но они являются тонкими и зависящими от реализации. Самый большой - то, что можно записать в именованный канал, прежде чем другой конец будет работать; с каналами без имени дескрипторы файлов совместно используются во время процесса ветвления/должностного лица, таким образом, нет никакого способа получить доступ к переходному буферу без закончившихся процессов.

Это имеет значение, какой конец канала я открываю сначала с именованными каналами?

Нет.

Действительно ли поведение каналов последовательно между различными системами Linux?

В причине, да. И т.д. могут варьироваться буферные размеры.

Поведение каналов зависят от оболочки, которую я использую или способ, которым я настроил его?

Нет. То, когда Вы создаете канал под покрытиями, что происходит, является Вашим родительским процессом (оболочка) создает канал, который имеет пару дескрипторов файлов, затем делает должностное лицо ветвления как этот псевдокод:

Родитель:

create pipe, returning two file descriptors, call them fd[0] and fd[1]
fork write-side process
fork read-side process

Сторона записи:

close fd[0]
connect fd[1] to stdout
exec writer program

Сторона чтения:

close fd[1]
connect fd[0] to stdin
exec reader program

Есть ли какие-либо другие вопросы, которые я должен задавать или проблемы, о которых я должен знать, если я хочу использовать каналы таким образом?

Все, Вы хотите сделать действительно попытку разметить в строке как это? В противном случае Вы могли бы хотеть думать о более общей архитектуре. Но понимание, что наличие большого количества отдельных процессов, взаимодействующих через "узкий" интерфейс канала, желательно, является хорошим.

[Обновленный: Мне инвертировали индексы дескриптора файла сначала. Они корректны теперь, видят man 2 pipe.]

4
ответ дан 3 November 2019 в 00:05
поделиться

Как Dashogun и Charlie Martin отметили, это - большой вопрос. Некоторые части их ответов неточны, таким образом, я собираюсь ответить также.

Я интересуюсь записью отдельных программных модулей, которые работают как независимые потоки, которые я мог сцепить вместе с каналами.

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

Если Вы действительно обращались к процессам, то это - основание классического подхода Unix к инструментам разработки. Многие стандартные программы Unix являются фильтрами, которые читают из стандартного входа, преобразовывают его так или иначе и пишут результат в стандартный вывод. Например, tr, sort, grep, и cat все фильтры, для именования только некоторые. Это - превосходная парадигма для следования, когда данные, которыми Вы управляете, разрешают его. Не все манипулирование данными способствует этому подходу, но существуют многие, которые являются.

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

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

Существует большое разнообразие возможностей здесь. Я использовал передачу по каналу некоторое время, но я незнаком с нюансами ее поведения.

Хорошо; задавание вопросов является одним (хорошим) способом учиться. Экспериментирование - другой, конечно.

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

Да. Существует предел размеру буфера канала. Классически, это было довольно маленьким - 4096, или 5120 были общие ценности. Можно найти, что современный Linux использует большее значение. Можно использовать fpathconf() и _PC_PIPE_BUF для обнаружения размера буфера канала. POSIX только требует, чтобы буфер был 512 (то есть, _POSIX_PIPE_BUF 512).

Если я пишу, что eof к потоку может я оставаться продолжить писать в тот поток, пока я не закрываю его?

Технически, нет никакого способа записать EOF в поток; Вы закрываете дескриптор канала для указания на EOF. Если Вы думаете об управлении-D или управлении-Z как символ EOF, то это - просто регулярные символы, что касается каналов - они только имеют эффект как EOF при вводе на терминале, который работает в каноническом режиме (приготовленный или нормальный).

Есть ли различия в названном поведении и каналы без имени?

Да, и нет. Самые большие различия - то, что каналы без имени должны быть настроены одним процессом и могут только использоваться тем процессом и детьми, которые совместно используют тот процесс как общий предок. В отличие от этого, именованные каналы могут использоваться ранее несвязанными процессами. Следующей большой разницей является последствие первого; с каналом без имени Вы возвращаете два дескрипторов файлов от единственной функции (система) вызов к pipe(), но Вы открываете FIFO или именованный канал с помощью постоянного клиента open() функция. (Кто-то должен создать FIFO с mkfifo() звоните, прежде чем можно будет открыть его; каналам без имени не нужна никакая подобная предшествующая установка.) Однако, после того как у Вас есть открытый дескриптор файла, существует драгоценное небольшое различие между именованным каналом и каналом без имени.

Это имеет значение, какой конец канала я открываю сначала с именованными каналами?

Нет. Первый процесс, который откроет FIFO, будет (обычно) блокироваться, пока не будет процесс с другим открытым концом. При открытии его для чтения и записи (aconventional, но возможный) затем, Вы не будете заблокированы; при использовании флага O_NONBLOCK Вы не будете заблокированы.

Действительно ли поведение каналов последовательно между различными системами Linux?

Да. Я не услышал об или испытал любые проблемы с каналами в любой из систем, где я использовал их.

Поведение каналов зависят от оболочки, которую я использую или способ, которым я настроил его?

Нет: каналы и FIFOs независимы от оболочки, которую Вы используете.

Есть ли какие-либо другие вопросы, которые я должен задавать или проблемы, о которых я должен знать, если я хочу использовать каналы таким образом?

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


Я наблюдал и выше и в комментариях к другим ответам, что буферы канала классически ограничены довольно небольшими размерами. @Charlie Martin противопрокомментировал, что некоторые версии Unix имеют динамические буферы канала и они могут быть довольно большими.

Я не уверен, которые он имеет в виду. Я использовал тестовую программу, которая следует Солярис, AIX, HP-UX, MacOS X, Linux и Cygwin / Windows XP (результаты ниже):

#include <unistd.h>
#include <signal.h>
#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>

static const char *arg0;

static void err_syserr(char *str)
{
    int errnum = errno;
    fprintf(stderr, "%s: %s - (%d) %s\n", arg0, str, errnum, strerror(errnum));
    exit(1);
}

int main(int argc, char **argv)
{
    int pd[2];
    pid_t kid;
    size_t i = 0;
    char buffer[2] = "a";
    int flags;

    arg0 = argv[0];

    if (pipe(pd) != 0)
        err_syserr("pipe() failed");
    if ((kid = fork()) < 0)
        err_syserr("fork() failed");
    else if (kid == 0)
    {
        close(pd[1]);
        pause();
    }
    /* else */
    close(pd[0]);
    if (fcntl(pd[1], F_GETFL, &flags) == -1)
        err_syserr("fcntl(F_GETFL) failed");
    flags |= O_NONBLOCK;
    if (fcntl(pd[1], F_SETFL, &flags) == -1)
        err_syserr("fcntl(F_SETFL) failed");
    while (write(pd[1], buffer, sizeof(buffer)-1) == sizeof(buffer)-1)
    {
        putchar('.');
        if (++i % 50 ==  0)
            printf("%u\n", (unsigned)i);
    }
    if (i % 50 !=  0)
        printf("%u\n", (unsigned)i);
    kill(kid, SIGINT);
    return 0;
}

Мне было бы любопытно получить дополнительные результаты других платформ. Вот размеры, которые я нашел. Все результаты больше, чем я ожидал, я должен признаться, но Charlie и я можем обсуждать значение 'довольно больших' когда дело доходит до буферных размеров.

  •  8196 - HP-UX 11.23 для IA-64 (fcntl (F_SETFL) отказавший)
  • 16384 - Солярис 10
  • 16384 - MacOS X 10.5 (O_NONBLOCK не работал, хотя fcntl (F_SETFL) не перестал работать),
  • 32768 - AIX 5.3
  • 65536 - Cygwin / Windows XP (O_NONBLOCK не работал, хотя fcntl (F_SETFL) не перестал работать),
  • 65536 - SuSE Linux 10 (и CentOS) (fcntl (F_SETFL) отказавший)

Одна точка, которая ясна из этих тестов, - то, что O_NONBLOCK работает с каналами на некоторых платформах а не на других.

Программа создает канал и ветвления. Ребенок закрывает конец записи канала и затем засыпает, пока это не получает сигнал - это - то, что делает пауза (). Родитель затем закрывает конец чтения канала и устанавливает флаги на дескрипторе записи так, чтобы он не блокировался на попытке записать на полном канале. Это затем циклы, пишущий один символ за один раз, и печатая точку для каждого записанного символа, и количество и новая строка каждые 50 символов. Когда это обнаруживает проблему записи (полный буфер, так как ребенок не читает вещь), это останавливает цикл, пишет заключительное количество и уничтожает ребенка.

4
ответ дан 3 November 2019 в 00:05
поделиться
Другие вопросы по тегам:

Похожие вопросы: