Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
ОСиСП теория 4 семестра - методичка слайдов Бранцевич Петр Юльянович 2009.doc
Скачиваний:
160
Добавлен:
15.06.2014
Размер:
1.75 Mб
Скачать

4.2 Неименнованные каналы (трубы)

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

#include <unistd.h>

Int pipe(int fd[2]);

Fd[0] – используется для чтения

Fd[1] – используется для записи

В результате выполнения системного вызова массив fd будет содержать два дискриптора файлов. А в случии ошибки переменная errno будет установлена:

EMFILE – превышено максимальное число дискрипторов для пользователя.

ENFILE – переполнение таблицы открытых файлов.

Действия по передаче данных производятся с помощью FIFO. Не допускаются никакие дествия по позиционированию.

#include <unistd.h>

#include <stdio.h>

#include <sys/types.h>

char *msg1=”AAAAAAAAA”;

char *msg2=”BBBBBBBBBB”;

char *msg3=”CCCCCCCCCC”;

int main()

{ char mbuf[MSG_S];

int p[2],i;

pid_t pid;

if(pipe(p)==-1)

{ printf(“Ошибка pipe \n”);

exit(1);

}

switch(pid=fork())

{ case -1: exit(2);

case 0: write(p[1],msg1,MSG_S);

write(p[1],msg2,MSG_S);

write(p[1],msg3,MSG_S);

break;

default : for(i=0; i<3;i++)

{ read(p[0],mbuf,MSG_S);

printf(“%s\n”,mbuf);

}

wait(NULL);

}

exit(0);

}

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

В большинстве UNIX-систем каналы однонаправленные, т.е. для чтения данных из канала используется fifo[0], а для записи - fifo[1]

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

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

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

Для реализации двунаправленной связи используют два канала.

4.2.1 Размер канала и взоимодействие процессов при передаче данных

Буфер, связанный с каналом, имеет конечный размер. Минимальный размер канала – 512 байт. При попытке записать данные в уже заполненный канал, ядро заблокирует процесс до тех пор, пока другой процесс не считает из канала достаточное количество данных, чтобы заблокированный процесс смог возобновить запись. Таким образом ядро системы пытается организовать в канал запись данных неделимой порцией. Действия функции чтения более простые. При её выполнении проверяется является ли канал пустым, если пуст, то функция чтения блокируется до тех пор, пока другой процесс не запишет данные в канал. А если же функция чтения запрашивает больше данных, чем есть в канале, то завершает выполнение после прочтения имеющихся в канале данных, даже если их меньше, чем функция запрашивает.

Интересные моменты: если больше нет процессов, которые могли бы выполнить запись в канал и канал при этом пуст, то любой процесс, который попытается выполнить чтение из канала получит пустой блок, а процессы, которые ожидали чтения из канала продолжат свою работу, а их вызовы чтения вернут 0-ое значение; если больше нет про процессов, которые могли бы выполнить чтение из канала, то ядро опирационной системы посылает сигнал SIGPIPE всем процессам ожидающим запись. По умолчанию этот сигнал приведет к остановке процесса. А если его перехватят, то после завершения процесса обработки, функция записи вернет значение -1, а переменная errno получит код EPIPE.

#include<unistd.h>

#include<fcntl.h>

#include<stdio.h>

#define MSG_S 7

char *msg1=”Привет”;

char *msg2=”Пока”;

int perent(int p[2])

{ int n_r;

char buf[MSG_S];

close(p[1]);

for(;;)

{ switch(n_r=read(p[0],buf,MSG_S))

{ case -1: if(errno==EAGAIN)

{ printf(“Канал пуст\n”);

sleep(1);

}

else

{ printf(“Ошибка read\n”);

exit(1);

}

case 0: printf(“Конец связи\n”);

exit(0);

default: printf(“MSG=%s\n”,buf);

}

}

}

int child(int p[2])

{ int i;

close (p[0]);

for(i=0;i<3;i++)

{ write(p[1],msg1,MSG_S);

sleep(3);

}

write(p[1],msg2,MSG_S);

exit(0);

}

main()

{ int pdf[2];

if(pipe(pdf)==-1)

{ printf(”Ошибка pipe\n”);

exit(1);

}

fcntf(pdf[0],F_SETFL,O_NONBLOCK);

switch(fork())

{ case -1: exit(1);

case 0 : child(pdf);

default: parent(pdf);

}

}