如何在Perl中加入所有线程

4
我的代码如下所示:
use threads;
use threads::shared;
use Thread::Queue;

my $q = Thread::Queue->new();
my @threads = ();
my $run :shared = 1;

$SIG{'TERM'} = sub {
    $run = 0;
    $q->enqueue('exit');
    foreach(@threads){
        $_->join();
    }
};

push @threads, threads->create(proc1);
push @threads, threads->create(proc2);

sub proc1 {

    while($p = $q->dequeue()){
        if($p eq 'exit'){
            last;
        }
        .....
    }
    $q->end();
    threads->exit();
}

sub proc2 {
    while($run){
       .....
    }
}

收到 TERM 信号时,我尝试等待所有线程结束。然而,每当我传递 TERM 信号时,我的程序都会因错误而终止。

Segmentation fault

如何修复这个问题?


你使用的 Perl 版本是什么? - ikegami
我正在使用 Perl 5.10.1。 - Kamrul Khan
我已经更新了代码,请现在检查一下。 - Kamrul Khan
1个回答

3

假设threads->create(proc1) 可以正常工作(这只可能是因为您没有像应该那样使用use strict;),则您的程序在创建线程后立即退出。您需要让主线程等待子线程完成。

修复该问题(并应用一些简化)将得到以下结果:

use strict;
use warnings;
use threads;
use threads::shared;
use Thread::Queue 3.01 qw( );

my $q = Thread::Queue->new();
my $run :shared = 1;

$SIG{TERM} = sub {
    print("Received SIGTERM. Shutting down...\n");
    $run = 0;
    $q->end();
};

print("$$\n");

threads->create(\&proc1);
threads->create(\&proc2);

$_->join() for threads->list();

sub proc1 {
    while(my $p = $q->dequeue()) {
        sleep 1;  # Placeholder
    }
}

sub proc2 {
    while($run){
        sleep 1;  # Placeholder
    }
}

我没有收到段错误,但程序也没有退出。信号处理程序根本没有被调用。这是因为Perl在调用信号处理程序之前等待join返回。您可以通过轮询可加入线程的列表来解决此问题。换句话说,替换原有的代码。

$_->join() for threads->list();

使用

my $running_threads = 2;
while ($running_threads) {
    for my $thread (threads->list(threads::joinable)) {
        $thread->join();
        $running_threads--;
    }

    sleep 1;
}

你能详细说明一下最后那个选择片段吗?我认为for循环将会“获取”所有没有while的线程。 - Sobrique
@Sobrique,就像我在答案中更详细地说的那样,是为了允许信号被处理。 - ikegami
建议您不要使用共享的$run,而是可以引用队列状态 - 通过读取$q->pending,您可以检测它是否已经结束(因为pending返回undef)。 - Sobrique
@Sobrique,这不是一个坏主意,但是那些工人似乎没有关联,所以这会引入不必要的耦合。 - ikegami
1
@user3360140,我好像在发布之前意外删除了我的答案的一部分。更新了我的答案以重新包含需要更改的原因。 - ikegami
@ikegami 非常感谢您的回复。基本上我不确定到底是什么导致了我的问题。现在我知道了,并且我还编写了一段代码,可以重现我遇到的错误。我开了一个新的线程,请查看 http://stackoverflow.com/questions/31279157/perl-seg-fault-while-joining-threads - Kamrul Khan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接