Вместо немедленной активизации того или иного исключения, выполнение функции die () откладывается до тех пор, пока в основном потоке не будет предпринята попытка вызвать с помощью метода join () поток, уничтоженный функцией die (). В этот момент выполняется функция die (), что приводит к завершению всей программы. Если метод join () потока, уничтоженного функцией die (), вызывается потоком, отличным от основного, действие функции die () снова откладывается до тех пор, пока не будет вызван с помощью функции jоin () и этот поток, например для предотвращения сбоя коммутируемой программы.
Для перехвата и обработки таких “отложенных” событий уничтожения с помощью функции die (), можно применить функцию eval (). Сообщение об ошибке, переданное функции die () будет записано в глобальную переменную $@.
my $pi = eval {$thread->join} || warn "Got an error: $@";
Простое многопоточное приложение
Ниже приведено очень простое многопоточное приложение. В нем порождается два новых потока, каждый из которых вызывает на выполнение подпрограмму hello (). Эта подпрограмма несколько раз выполняет цикл и выводит сообщение, передаваемое вызывающей процедурой. Эта подпрограмма переходит в состояние ожидания на короткое время при каждом проходе по циклу (это сделано только в иллюстративных целях, а не для обеспечения параллельной работы потоков). После запуска двух потоков основной поток переходит в состояние ожидания завершения двух этих потоков, вызвав метод join ().
# !./usr/bin/perl use Thread; my $thread1 = Thread->new(&hello, "I am thread 1",3) my $thread2 = Thread->new(&hello, "I am thread 2",6) $_->join foreach ($threadl, $thread2); sub hello { my ($message,$loop) = @_; for (l..$loop) { print $message, "n"; sleep 1; } }
Блокировка
Основная проблема при работе с потоками возникает, как только два потока предпринимают попытку одновременно изменить одну и ту же переменную. Для иллюстрации этого рассмотрим следующий обманчиво простой фрагмент кода.
my $bytes_sent = 0; my $socket = IO::Socket->new(....); sub send_datal { my $data = shift my $bytes = $socket->syswrite($data); $bytes_sent += $bytes; }
Проблема возникает в последней строке подпрограммы, где наращивается значение переменной $bytes_sent. Если работает сразу несколько сетевых соединении, события могут развиваться по крайне нежелательному сценарию.
Решение этой проблемы, может состоять в вызове функции lock () для блокировки переменной $bytes_sent перед попыткой ее использовать. После этого небольшого изменения сценарий будет работать правильно.