У меня есть сценарий Perl, который запускает 2 потока, один для каждого процессора. Мне нужен он для ожидания потока для окончания, если один поток заканчивается порожден, новый. Кажется, что остальная часть блоков метода соединения программы, поэтому второй поток не может закончиться до всего, что первый поток делает сделан который вид поражений его цель.
Я попробовал is_joinable
метод, но это, кажется, не делает это также.
Вот часть моего кода:
use threads;
use threads::shared;
@file_list = @ARGV; #Our file list
$nofiles = $#file_list + 1; #Real number of files
$currfile = 1; #Current number of file to process
my %MSG : shared; #shared hash
$thr0 = threads->new(\&process, shift(@file_list));
$currfile++;
$thr1 = threads->new(\&process, shift(@file_list));
$currfile++;
while(1){
if ($thr0->is_joinable()) {
$thr0->join;
#check if there are files left to process
if($currfile <= $nofiles){
$thr0 = threads->new(\&process, shift(@file_list));
$currfile++;
}
}
if ($thr1->is_joinable()) {
$thr1->join;
#check if there are files left to process
if($currfile <= $nofiles){
$thr1 = threads->new(\&process, shift(@file_list));
$currfile++;
}
}
}
sub process{
print "Opening $currfile of $nofiles\n";
#do some stuff
if(some condition){
lock(%MSG);
#write stuff to hash
}
print "Closing $currfile of $nofiles\n";
}
Вывод этого:
Opening 1 of 4
Opening 2 of 4
Closing 1 of 4
Opening 3 of 4
Closing 3 of 4
Opening 4 of 4
Closing 2 of 4
Closing 4 of 4
Я думаю, вам нужно переместить код, который извлекает следующий файл из списка, в сами потоки.
Таким образом, каждый поток будет не просто обрабатывать один файл, но продолжать обработку до тех пор, пока список не станет пустым.
Таким образом, вы также экономите на постоянном создании новых потоков.
Ваш основной поток затем присоединится к ним обоим.
Конечно, для этого требуется синхронизация списка (чтобы они не извлекали одни и те же данные). В качестве альтернативы вы можете разделить список на два (по одному для каждого потока), но это может привести к неудачному распределению.
(PS: Нет Perl God, просто скромный монах)
Прежде всего, несколько замечаний по самому коду. Вы должны убедиться, что у вас есть:
use strict;
use warnings;
в начале каждого скрипта. Во-вторых:
@file_list = @ARGV; #Our file list
$nofiles = $#file_list + 1; #Real number of files
не нужен, так как массив в скалярном контексте оценивается по количеству элементов в массиве. То есть:
$nofiles = @ARGV;
правильно выдаст вам количество файлов в @ARGV
независимо от значения $[
.
Наконец, сценарий можно значительно упростить, разбив список файлов на разделы перед запуском потоков:
use strict; use warnings;
use threads;
use threads::shared;
my @threads = (
threads->new(\&process, @ARGV[0 .. @ARGV/2]),
threads->new(\&process, @ARGV[@ARGV/2 + 1 .. @ARGV - 1]),
);
$_->join for @threads;
sub process {
my @files = @_;
warn "called with @files\n";
for my $file ( @files ) {
warn "opening '$file'\n";
sleep rand 3;
warn "closing '$file'\n";
}
}
Output:
C:\Temp> thr 1 2 3 4 5 called with 1 2 3 opening '1' called with 4 5 opening '4' closing '4' opening '5' closing '1' opening '2' closing '5' closing '2' opening '3' closing '3'
Или же можно позволить потокам переходить к следующей задаче по мере ее выполнения:
use strict; use warnings;
use threads;
use threads::shared;
my $current :shared;
$current = 0;
my @threads = map { threads->new(\&process, $_) } 1 .. 2;
$_->join for @threads;
sub process {
my ($thr) = @_;
warn "thread $thr stared\n";
while ( 1 ) {
my $file;
{
lock $current;
return unless $current < @ARGV;
$file = $ARGV[$current];
++ $current;
}
warn "$thr: opening '$file'\n";
sleep rand 5;
warn "$thr: closing '$file'\n";
}
}
Output:
C:\Temp> thr 1 2 3 4 5 thread 1 stared 1: opening '1' 1: closing '1' 1: opening '2' thread 2 stared 2: opening '3' 2: closing '3' 2: opening '4' 1: closing '2' 1: opening '5' 1: closing '5' 2: closing '4'