logo
Конспект Граур

Пример. Двухпроцессный вариант программы “Будильник”.

#include <signal.h>

#include <sys/types.h>

#include <unistd.h>

#include <stdio.h>

void alr(int s)

{

printf(“\n Быстрее!!! \n”);

signal(SIGALRM, alr);

/* переустановка обработчика alr на приход сигнала SIGALRM */

}

int main(int argc, char **argv)

{

char s[80];

int pid;

signal(SIGALRM, alr);

/* установка обработчика alr на приход сигнала SIGALRM */

if (pid = fork()) {

for (;;)

{

sleep(5); /*приостанавливаем процесс на 5 секунд */

kill(pid, SIGALRM);

/*отправляем сигнал SIGALRM процессу- сыну */

}

}

else {

printf(“Введите имя \n”);

for (;;)

{

printf(“имя:”);

if (gets(s) != NULL) break; /*ожидаем ввода имени*/

}

printf(“OK!\n”);

kill(getppid(), SIGKILL);

/* убиваем зациклившегося отца */

}

return 0;

}

В данном случае программа реализуется в двух процессах. Как и в предыдущем примере, имеется функция реакции на сигнал alr(), которая выводит на экран сообщение и переустанавливает функцию реакции на сигнал, опять же на себя. В основной программе мы также указываем alr() как реакцию на SIGALRM. После этого мы запускаем сыновний процесс, и отцовский процесс (бесконечный цикл) “засыпает” на 5 единиц времени, после чего сыновнему процессу будет отправлен сигнал SIGALRM. Все, что ниже цикла, будет выполняться в процессе-сыне: мы ожидаем ввода строки, если ввод осуществлен, то происходит уничтожение отца (SIGKILL).

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

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

Отличитльные свойства:

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

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

  3. Канал не существует вне процессора, его породившего. Он является ресурсом, который создал тот или иной процесс, и если породивший его процесс завершается, то и канал уничтожается. Т.е. точно так же, как все открытые файлы закрываются и прочие ресурсы освобождаются при завершении процесса, так один из этих ресурсов это и канал, который в этом случае тоже освобождается. И соответственно если файл при этом сохраняется на диске, то содержимое канала исчезает бесследно.

  4. Главное отличие от файла – это то, что в нем реализуется строго последовательный доступ к данным. Это означает, что данные могут быть получены только в том порядке, в котором они были в канал положены. Если в файле был возможен произвольный доступ к данным, то в канале это невозможно.

Одним из простейших средств взаимодействия процессов в операционной системе UNIX является механизм каналов. Неименованный канал есть некая сущность, в которую можно помещать и извлекать данные, для чего служат два файловых дескриптора, ассоциированных с каналом: один для записи в канал, другой — для чтения. Для создания канала служит системный вызов pipe():

int pipe (int *fd)

 

Данный системный вызов выделяет в оперативной памяти некоторое ограниченное пространство и возвращает че6рез параметр fd массив из двух файловых дескрипторов: один для записи в канал — fd[1], другой для чтения — fd[0].

 

Эти дескрипторы являются дескрипторами открытых файлов, с которыми можно работать, используя такие системные вызовы как read(), write(), dup() и пр.

Однако существуют различия в организации использования обычного файла и канала.

Особенности организации чтения данных из канала:

    если прочитано меньше байтов, чем находится в канале, оставшиеся сохраняются в канале;

   если делается попытка прочитать больше данных, чем имеется в канале, и при этом существуют открытые дескрипторы записи, ассоциированные с каналом, будет прочитано (т.е. изъято из канала) доступное количество данных, после чего читающий процесс блокируется до тех пор, пока в канале не появится достаточное количество данных для завершения операции чтения;

  процесс может избежать такого блокирования, изменив для канала режим блокировки с использованием системного вызова fcntl(), в этом случае будет считано доступное количество данных, и управление будет сразу возвращено процессу;

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

 

 

Особенности организации записи данных в канал:

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

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

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

        если процесс пытается осуществить запись в канал, с которым не ассоциирован ни один дескриптор чтения, то он получает сигнал SIGPIPE (тем самым ОС уведомляет его о недопустимости такой операции).

 

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