Читаем Язык программирования Perl полностью

Рис. 16.2.  Присоединение нити с помощью join()

Каждой нити присваивается числовой идентификатор (Thread Identifier, TID), который можно получить с помощью метода tid. Создание нескольких нитей, объединение потоков и возврат значений из параллельно выполняющихся подпрограмм можно показать на таком примере:

use threads; # подключить многопоточные средства my @thread = (); # массив объектов типа threads for (my $i = 0; $i <= 2; $i++) { # создаем 3 нити $thread[$i] = threads->new(\&pearl_thread, $i); print "Создана $i-я нить. TID=", $thread[$i]->tid, "\n"; } for (my $i = 2; $i >= 0; $i--) { # присоединяем нити print "$i-я нить вернула ", $thread[$i]->join, "\n"; } sub pearl_thread ($) { # нить получает my $number = shift; # число, генерирует my $random = int(rand(7)) + 1; # случайное значение, print "\t$number-я нить ждет $random сек.\n"; sleep $random; # и, подождав немного, return $random; # возвращает его }

Сообщения, выводимые при выполнении этой программы, подтверждают независимое выполнение нитей и основной программы:

Создана 0-я нить. TID=1 Создана 1-я нить. TID=2 1-я нить ждет 7 сек. 0-я нить ждет 1 сек. Создана 2-я нить. TID=3 2-я нить ждет 3 сек. 2-я нить вернула 3 1-я нить вернула 7 0-я нить вернула 1

Параллельно выполняющийся поток можно "отсоединить", игнорируя его значение: это делается методом $thread->detach, после выполнения которого присоединить нить будет невозможно.

Нити, выполняющиеся параллельно с основной программой, могут иметь доступ к общим переменным: скалярам, массивам и хэшам. Это делается с помощью явного указания для разделяемой переменной атрибута shared. Помеченная этим атрибутом переменная будет доступна для чтения и изменения в параллельном потоке. Для остальных переменных при отсоединении нити создаются локальные для каждого потока копии. Это демонстрируется таким примитивным примером:

use threads; # подключить многопоточные средства use threads::shared; # и средства разделения данных my $public : shared = 0; # разделяемая переменная my $private = 0; # неразделяемая переменная threads->new(sub { # нить из анонимной подпрограммы $public++; $private++; # изменяем значения print "$public $private\n"; # будет выведено: 1 1 })->join; # дожидаемся результатов выполнения: print "$public ", # 1 ($public изменена в нити) "$private\n"; # 0 (в нити изменена копия $private)

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

{ # блок для работы с разделяемой переменной lock $variable; # заблокировать переменную $variable = $new_value; # и изменить ее значение } # здесь $variable автоматически разблокируется

Перейти на страницу:

Похожие книги