- •Лекция-1:
- •Лекция-2:
- •Лекция-3:
- •Лекция-4:
- •Лекция-5:
- •Лекция-6:
- •Лекция-7:
- •Лекция-8:
- •Лекция-9:
- •Лекция-10:
- •Лекция-11:
- •Лекция-12:
- •Лекция-13:
- •Лекция-14:
- •Лекция-14:
- •Лекция-15:
- •Лекция-16:
- •Лекция-17:
- •Лекция-18:
- •Лекция-19:
- •Применение алгоритма банкира
- •Лекция-20:
- •Лекция-21
- •Лекция-22
- •Лекция-23
- •Лекция-24
Лекция-7:
Количество процессов, которые могут присоединиться к каналу, принципиально не ограничено. Однако если два или более процессов записывают в канал данные, то величина записи каждого из процессов ограничена определенной в системе величиной. Через некоторое время найдется процесс, считывающий данные из канала, после этого опять очередь перейдёт к данному процессу и он дозапишет информацию.
Для предотвращения такого недостатка коммуникационный канал обычно делают однонаправленным и используют его для связи между двумя процессами, причем один процесс является отправителем, а другой получателем. Если оба процесса требуют при взаимодействии как операции передачи, так и операции приема, то целесообразно для связи между ними создать два канала.
Если дескриптора файла, связанного с записывающей стороной канала не существует, то эта сторона считается закрытой и любой процесс, пытающиеся считать данные из канала, получает оставшиеся в нем данные. Если все данные прочитаны, то получает признак конца файла. Если же не существует дескриптора файла, связанного с читающей стороной канала, а процесс пытается записать данные в канал, то ядро формирует для данного канала сигнал SIGPIPE. Действие по умолчанию на этот сигнал завершение процесса.
В этом примере родительский процесс определяется как получатель, который читает сообщения порожденного процесса с помощью дескриптора fifo[0], причем родительский процесс сначала закрывает на запись дескриптор fifo[1]. Это требуется для того, чтобы записывающая сторона канала закрылась, когда процесс-сын после передачи данных в канал закрывает свой дескриптор fifo[1]. Процесс-сын закрывает дескриптор на чтение, а потом производит запись данных в канал, а родитель читает данные, а потом закрывает канал на чтение. Если сын не закроет канал, отец не получит признака конца файла.
Сигналы
Сигналы являются средством передачи уведомления о некотором произошедшем событии между процессами или между ядром системы и процессами. Сигналы рассматриваются как форма межпроцессорного взаимодействия, хотя по сути напоминают прерывания, генерируемые при нарушении нормального выполнения процесса. Каждый сигнал имеет уникальное имя и имеются два системных вызова для генерации сигналов.
#include <sys/types.h>
#include <signal.h>
int kill (pid_t pid, int sig);
int raise (int sig);
Системный вызов kill посылает сигнал процессу или группе процессов. Тип сигнала определяется аргументом sig, а первый аргумент определяет, кому посылается сигнал.
Если PID>0, сигнал посылается процессу, идентификатор которого равен PID.
Если PID=0, то сигнал посылается всем процессам из группы процессов, к которой принадлежит процесс, посылающий сигнал.
Если PID<1, то сигнал посылается всем процессам, идентификатор группы которых равен абсолютному значению pid.
Второй системный вызов raise предназначается для генерации сигнала sig для текущего процесса.
Системные вызовы возвращают 0 в случае успешной посылки сигнала. Kill в случае ошибки возвращает –1, а raise – ненулевое значение. В случае ошибки обнаруживаются ошибочные ситуации:
EINVAL
EPERM
ESRCH
Первая ошибочная ситуация означает, что аргумент не является сигналом. Вторая что процесс не правомочен посылать сигнал указанному принимающему процессу. Третья аргумент PID не является идентификатором процесса или группы процессов. К генерации процесса могут привести следующие ситуации:
Ядро посылает процессу или группе процессов сигнал при нажатии пользователем определенных клавиш или их комбинаций (например, Ctrl-C).
Аппаратные особые ситуации (деление на 0, обращение к недопустимой области памяти, нарушение защиты памяти, отсутствие требуемой страницы в памяти и т.д.). Обычно эти ситуации определяются аппаратурой машины, и ядру операционной системы посылаются соответствующие уведомления, например, в виде прерывания, а ядро реагирует на такое событие отправкой соответствующего сигнала процессу, который находился в стадии выполнения, когда произошла особая ситуация.
Определенные программные состояния системы или ее компонентов. Эти причины имеют чисто программный характер. К такой ситуации относится посылка сигнала по срабатыванию таймера, установленного с помощью специального системного вызова alarm. При получении сигнала может быть выбрано одно из следующих действий реагирования:
игнорирование сигнала
перехват и самостоятельная обработка сигнала
выполнение действия по умолчанию
Есть два сигнала (SIGKILL и SIGSTOP), которые невозможно ни игнорировать, ни перехватывать.
Существует определенный набор сигналов. В качестве действия по умолчанию:
завершение текущего процесса
завершение и создание файла alarm
игнорирование.
Для определения собственных обработчиков сигналов имеются специальные системные вызовы. Самый простейший вызов сигнала:
Пример:
#include <signal.h>
void (* signal (int sig, void (* disp)(int)))(int);
static void sig_hndlr (int signv);
{
signal (SIGINT,sig_hndlr);
printf (“Получен сигнал SIGINT\n”);
//функция обработки сигнала
}
main( )
{
signal (SIGINT,sig_hndlr);
signal (SIGUSR1,SIG_DFL);
//действие по умолчанию системы
signal (SIGUSR2,SIG_IGN);
//который игнорируется
while (1);
pause ( );
}