Опубликован: 17.08.2006 | Доступ: свободный | Студентов: 5387 / 708 | Оценка: 4.49 / 3.94 | Длительность: 20:58:00
ISBN: 978-5-9556-0078-9
Лекция 16:

Взаимодействие процессов

< Лекция 15 || Лекция 16: 1234 || Лекция 17 >

Сигналы и их обработка

В операционных системах имеется механизм, который может доставлять процессу уведомление о наступлении какого-либо события. Этот механизм основан на так называемых сигналах. Работа с ними происходит следующим образом. В программе может быть определен обработчик того или иного сигнала, который автоматически вызывается, когда ОС доставляет сигнал процессу. Сигналы могут отправляться операционной системой, или один процесс может с помощью ОС послать сигнал другому. Процесс, получивший сигнал, сам решает, каким образом реагировать на него, - например, он может проигнорировать сигнал. Перечень сигналов, получение которых можно попытаться обработать, находится в специальном хэше с именем %SIG. Поэтому допустимые идентификаторы сигналов можно вывести функцией keys(%SIG). Общеизвестный пример - сигнал прерывания выполнения программы INT, который посылает программе операционная система по нажатию на консоли сочетания клавиш Ctrl+C. Как устанавливать обработчик конкретного сигнала, показано на примере обработки сигнала INT:

# устанавливаем обработчик сигнала INT
$SIG{INT} = \&sig_handler; # ссылка на подпрограмму
# начало основной программы
print "Работаю в поте лица...\n" while (1); # бесконечный цикл

sub sig_handler { # подпрограмма-обработчик сигнала
   $SIG{INT} = \&sig_handler; # переустанавливаем обработчик
   print "Получен сигнал INT по нажатию Ctrl+C\n"; 
   print "Заканчиваю работу!\n"; 
   exit; # завершение выполнения программы
}

Выполнение примера сопровождается выводом сообщений, подтверждающих обработку поступившего сигнала:

Работаю в поте лица...
Получен сигнал INT по нажатию Ctrl+C
Заканчиваю работу!

Примером реальной программы, выполняющейся в бесконечном цикле, может служить любой сервер, ожидающий запросов от клиентских программ и перечитывающий свой конфигурационный файл после получения определенного сигнала (обычно HUP или USR1). Если необходимо временно игнорировать какой-то сигнал, то соответствующему элементу хэша %SIG присваивается строка 'IGNORE'. Восстановить стандартную обработку сигнала можно, присвоив соответствующему элементу %SIG строку 'DEFAULT'.

Процесс может посылать сигналы самому себе, например, для отслеживания окончания запланированного периода времени (для обработки тайм-аута). В приведенном примере длительная операция прерывается по истечении указанного промежутка времени:

# устанавливаем обработчик сигнала ALRM (будильник)
$SIG{ALRM} = sub { die "Timeout"; }; # анонимная подпрограмма
$timeout = 3600;    # определяем величину тайм-аута (сек.)
eval {              # блок обработки возможной ошибки
   alarm($timeout); # устанавливаем время отправки сигнала
                    # некая длительная операция:
   print "Работаю в поте лица...\n" while (1);
   alarm(0);        # нормальное завершение операции
};
# в специальной переменной $@ - сообщение об ошибке
if ($@ =~ /Timeout/) { # проверяем причину ошибки 
   print "Аварийный выход по истечении времени!";
}

Отправка сигнала одним процессом другому также используется в качестве средства взаимодействия процессов. Сигнал отправляется процессу с помощью функции kill(), которой передаются два аргумента: номер сигнала и PID процесса. Схему реагирования порожденного процесса на сигналы, получаемые от процесса-предка, можно увидеть на следующем учебном примере:

my $parent = $$;  # PID родительского процесса
my $pid = fork(); # 'разветвить' текущий процесс
# fork вернет PID потомка в процессе-предке и 0 в потомке 
die "fork не отработал: $!" unless defined $pid;
if ($pid) { # ---------- родительский процесс ----------
   print "Начался предок PID $$\n";
   for (1..3) {
      print "Предок PID $$ работает $_\n";
      print "Предок PID $$ отправил сигнал\n";
      kill HUP, $pid;
      sleep 2;       # 'заснуть' на 2 секунды
   }
   print "Закончился предок (PID $$)\n";
}
unless ($pid) { # ---------- дочерний процесс ----------
   my $counter = 0;  # счетчик полученных сигналов
   $SIG{HUP} = sub { ### обработчик сигнала ###
      $counter++;
      print "\tПотомок получил $counter-й сигнал!\n"; 
   };                ### конец обработчика сигнала ###
   print "\tНачался потомок PID $$ предка $parent\n";
   for (1..7) {
      print "\tПотомок PID $$ работает $_\n";
      sleep 1;       # 'заснуть' на 1 секунду
   }
   print "\tЗакончился потомок PID $$\n";
}

Поведение этих процессов во время выполнения программы можно проследить по выводимым ими сообщениям:

Начался потомок PID -800 предка 696
        Потомок PID -800 работает 1
	Начался предок PID 696
	Предок PID 696 работает 1
	Предок PID 696 отправил сигнал
	        Потомок получил 1-й сигнал!
	        Потомок PID -800 работает 2
	Предок PID 696 работает 2
	Предок PID 696 отправил сигнал
	        Потомок PID -800 работает 3
	        Потомок получил 2-й сигнал!
	        Потомок PID -800 работает 4
	Предок PID 696 работает 3
	Предок PID 696 отправил сигнал
	        Потомок PID -800 работает 5
	        Потомок получил 3-й сигнал!
	        Потомок PID -800 работает 6
	Закончился предок (PID 696)
	        Потомок PID -800 работает 7
	        Закончился потомок PID -800

Сигналы нельзя считать слишком надежным и информативным средством обмена информацией: для передачи данных лучше использовать другие способы. Зато можно проверить состояние дочернего процесса, отправив ему особый нулевой сигнал функцией kill(0, $pid). Этот вызов не влияет на выполнение процесса-потомка, но возвращает истину (1), если процесс "жив", и ложь (0), если он завершился или ему нельзя посылать сигналы. Одинаковая реакция на нулевой сигнал гарантируется на различных платформах. Кроме того, можно прекратить выполнение дочернего процесса, отправив ему сигнал KILL вызовом kill(KILL, $pid).

< Лекция 15 || Лекция 16: 1234 || Лекция 17 >
Сергей Крупко
Сергей Крупко

Добрый день.

Я сейчас прохожу курс  повышения квалификации  - "Профессиональное веб-программирование". Мне нужно получить диплом по этому курсу. Я так полагаю нужно его оплатить чтобы получить диплом о повышении квалификации. Как мне оплатить этот курс?

 

Галина Башкирова
Галина Башкирова

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

Системный администратор информационно-коммуникационных» систем.
Мне нужно самой найти тему? или делать по высланным темам