Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
К.Р. Вариант 2.docx
Скачиваний:
2
Добавлен:
24.09.2019
Размер:
32.12 Кб
Скачать

Установка обработчитка сигнала. Системные вызовы signal и sigaction. Синхронизация процессов при помощи сигналов. Системные вызовы sleep и pause. Установка обработчика сигнала.

Существуют две базовые стратегии, используемые при разработке функций-обработчиков:

1. при поступлении сигнала функция выполняет некоторое действие и возвращает управление в программу;

2. функция прерывает выполнение программы или исправляет ситуацию, возникшую в результате ошибки.

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

Обработчики первого типа используются для сигналов ‘SIGALRM’, сигналов, поступающих от устройств ввода-вывода. Обработчик должен изменять некоторую глобальную переменную в знак того, что обработчик получил управление. Тип данных этой переменной должен быть sig_atomic_t.

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

volatile sig_atomic_t fatal_error_in_progress = 0;

void

fatal_error_signal (int sig)

{

if (fatal_error_in_progress)

raise (sig);

fatal_error_in_progress = 1;

...

signal (sig, SIG_DFL);

raise (sig);

}

Если запущен обработчик для конкретного сигнала, то этот сигнал блокируется до тех пор, пока работа обработчика не будет завершена. Тем не менее, работа обработчика может быть прервана приходом какого-либо другого сигнала. Для того, чтобы избежать этого нужно использовать поле sa_mask структуры sigaction, чтобы указать какие сигналы будут заблокированы в процессе выполнения обработчика.

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

• если обработчику необходимо работать с глобальной переменной, определенной в программе, то она должна быть определена как volatile, что говорит компилятору о возможности изменения ее асинхронно;

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

Синхронизация процессов при помощи сигналов.

Сигналы можно использовать для синхронизации (координации действий) процессов при обмене данными. Один процеесс (процесс-писатель) готовит данные, а другой (процесс-читатель) - их обрабатывает. Если сигналы поступают от внешнего источника синхронизации, например, от системного таймера, то такой обмен данными называется синхронным. При этом оба процесса должны успеть выполнить свою работу в интервале времени между сигналами. При асинхронном обмене обмен данными осуществляется по готовности процессов: процесс-писатель уведомляет сигналом процесс-читатель о том, что данные готовы и их можно считывать. А процесс-читатель в свою очередь уведомляет также сигналом процесс-писатель о том, что данные обработаны и их можно перезаписать. При этом скорость обмена данными будет максимально возможной, и в то же время будет исключена возможность как перезаписи необработанных данных, так и повторной обработки одних и тех же данных. При большом объеме работы при подготовке или обработке данных есть риск, что при синхронном обмене, когда оба процесса (писатель и читатель) получают сигналы от таймера реального времени с одним и тем же интервалом, обработка сигнала от таймера в одном из процессов не будет завершена, а управление будет передано обработчику сигнала от таймера в другом процессе. Также есть риск того, что обработчики сигналов будут активизироваться не всегда в одной и той же последовательности. Например, на первый сигнал от таймера вначале сработает "читатель", а за ним - "писатель", а на следующий сигнал - вначале "писатель, а затем "читатель". Для того, чтобы избежать подобных проблем, особенно, если вероятен перенос программ на другую платформу, рекомендуется сделать частоту сигналов от таймера реального времени в 2 раза больше и модифицировать код обработчиков сигнала таким образом, чтобы один из них выполнял работу по четным сигналам, а другой - по нечетным.

Сигналы могут инициироваться не только ядром ОС. Один процесс может послать сигнал другому процессу при помощи системного вызова kill. Обычно для этого используются два специальных пользовательских сигнала SIGUSR1 и SIGUSR2. Если при поступлении сигнала процесс находится в состоянии "сна", то он пробуждается. Таким образом сигнал может досрочно завершить функцию sleep. Если же требуется перевести процесс в неактивное состояние не на заданный интервал времени, а до поступления сигнала, то для этого используется системный вызов pause. Из неактивного состояния после вызова pause процесс выводится любым сигналом. Если же требуется реакция на строго определенный сигнал и есть вероятность поступления других сигналов, то лучше использовать системный вызов sigsuspend. Сигналы можно использовать для синхронизации (координации действий) процессов при обмене данными. Один процеесс (процесс-писатель) готовит данные, а другой (процесс-читатель) - их обрабатывает. Если сигналы поступают от внешнего источника синхронизации, например, от системного таймера, то такой обмен данными называется синхронным. При этом оба процесса должны успеть выполнить свою работу в интервале времени между сигналами. При асинхронном обмене обмен данными осуществляется по готовности процессов: процесс-писатель уведомляет сигналом процесс-читатель о том, что данные готовы и их можно считывать. А процесс-читатель в свою очередь уведомляет также сигналом процесс-писатель о том, что данные обработаны и их можно перезаписать. При этом скорость обмена данными будет максимально возможной, и в то же время будет исключена возможность как перезаписи необработанных данных, так и повторной обработки одних и тех же данных. При большом объеме работы при подготовке или обработке данных есть риск, что при синхронном обмене, когда оба процесса (писатель и читатель) получают сигналы от таймера реального времени с одним и тем же интервалом, обработка сигнала от таймера в одном из процессов не будет завершена, а управление будет передано обработчику сигнала от таймера в другом процессе. Также есть риск того, что обработчики сигналов будут активизироваться не всегда в одной и той же последовательности. Например, на первый сигнал от таймера вначале сработает "читатель", а за ним - "писатель", а на следующий сигнал - вначале "писатель, а затем "читатель". Для того, чтобы избежать подобных проблем, особенно, если вероятен перенос программ на другую платформу, рекомендуется сделать частоту сигналов от таймера реального времени в 2 раза больше и модифицировать код обработчиков сигнала таким образом, чтобы один из них выполнял работу по четным сигналам, а другой - по нечетным. При асинхронном обмене процессы обмениваются сигналами следующим образом:

while(...){ while(...){

pause(); kill(...,SIGUSR1);

kill(...,SIGUSR1); pause();

} } Однако, такая простая последовательность может привести к "клинчу" - ситуации, когда оба процесса вошли в паузу и ждут сигналов друг от друга. Это возможно в случае, если планировщик процессов приостановит процесс до вызова pause, и ответный сигнал проскочит до входа в паузу; или же в том случае, если процесс "справа" зайдет в цикл раньше, чем процесс "слева". Повысить надежность асинхронного обмена можно при помощи вспомогательных глобальных переменных, называемых "сигнальными", которые предотвращают вход процесса в паузу, если ожидаемый сигнал уже поступил, и таким образом снижают вероятность возникновения "клинча":