Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Конспект 58 страниц 2002.doc
Скачиваний:
91
Добавлен:
15.06.2014
Размер:
4.07 Mб
Скачать

Средства ВзаимодействиЯ между процессАми

Неименованные каналы.

#include <unistd.h>

int pipe(int fifo[2]);

Системный вызов pipe(), который создаёт коммуникационный канал, между двумя взаимосвязанными процессами, например: между отцом и сыном или двумя процессами, порождёнными одним родительским процессом. Эта функция создаёт файл канала, который является временным буфером и использующийся для того, чтобы вызывающий процесс мог записывать туда данные для других процессов и считывать данные для себя от других процессов. Файлу канала имя не присваивается, поэтому он и называется “неименованный ”. Канал освобождается сразу после того, как все процессы закроют файловые дескрипторы, ссылающиеся на этот канал.

Аргумент системного вызова pipe()  массив из двух целых чисел. Для чтения данных из канала используется элемент fifo[0], а для записи  fifo[1]. При успешном завершении pipe() возвращает 0, а при ошибке -1.

К данным, хранящимся в канале, доступ производится последовательно по принципу First In First Out. Процесс не может использовать функции позиционирования в канале. Данные удаляются из канала сразу после считывания.

Можно определить две типовые схемы взаимодействия через канал:

  1. Отец <-> сын: родительский процесс использует pipe() для создания канала, а затем с помощью fork () порождает процесс-сын. Порожденный процесс имеет копию дескрипторов файлов процесса-отца, и процесс-отец и процесс-сын могут взаимодействовать через fifo[0] и fifo[1]

  2. Брат <-> брат: отец сначала производит системный вызов pipe(), а затем порождаются 2 или более сыновей-братьев. Процессы-братья взаимодействуют между собой через fifo[0] и fifo[1]

Программа взаимодействия отца с сыном.

#include <iosream.h>

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <sys/types.h>

#include <sys/wait.h>

#include <unistd.h>

int main()

{

pid_t child_pid, pid;

int status, fifo[2];

char buf[80];

if (pipe(fifo)==-1) perror (“pipe”); _exit(1);

switch(child_pid=fork())

{

case -1 : perror (“fork”); _exit(2);

case 0 : close(fifo[0]); //сын

write(fifo[1], “сын %d завершил работу \n”, getpid());

close(fifo[1]);

_exit(0);

}

close(fifo[1]); // отец

while (read(fifo[0],buf,80)) printf(“\n %s\n”,buf);

close(fifo[0]);

if ((waitpid(child_pid, &status, 0)==child_pid) && WIFEXITED(status))

return(WEXITSTATUS(status));

return(3);

}

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

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

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

Двунаправленный канал

Два однонаправленных канала

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

Есть системные вызовы, контролирующие работу с каналами.