1

我在从线程访问包变量时遇到问题。这是一个大项目,所以我将尝试提取代码的相关部分。

我将线程模块和Moose用于 OO 部分。

our $thread2;

around 'new' => sub {
  [...]
  threads->create( \&_thread1Func, $shared_self );
  if (!$thread2) {
    $thread2 = threads->create( \&_thread2Func, $shared_self );
    $thread2->detach();
  }
}

sub _thread1Func {
  $thread2->kill('SIGUSR1');
}

sub _thread2Func {
  $SIG{'USR1'} = sub { [...] };
  while (1) {
    sleep 5;
    [...]
  }
}

我收到以下错误:

Thread N terminated abnormally: Can't call method "kill" on an undefined value at XXXX.pm line n.

指向n线$thread2->kill('SIGUSR1');

我在想用 $thread2 声明our它可以从整个包中看到。

知道发生了什么吗?

4

2 回答 2

3

perldoc 线程中所述:

从 Perl 5.8 开始,线程编程可以使用一种称为解释器线程的模型,它为每个线程提供一个新的 Perl 解释器,并且默认情况下,线程之间不会共享任何数据或状态信息。

our“为当前包中同名的包变量创建一个词法别名,以便在当前词法范围内使用。”

这并不意味着它创建了一个在线程之间共享的变量。为此,您需要threads::shared。但是,请注意:

该模块仅支持以下数据类型的共享:标量和标量引用、数组和数组引用以及哈希和哈希引用。

你的代码对我来说看起来很麻烦。如果您解释为什么要这样做,我们可能会提供更具体的帮助。

以下可能会做一些接近你想要的事情:

#!/usr/bin/env perl

use strict;
use warnings;

use threads;
use threads::shared;

my $thread2_tid :shared;

sub myfunc {
    threads->create(\&_thread1Func);
    if (!$thread2_tid) {
        my $thread2 = threads->create(\&_thread2Func);
        $thread2_tid = $thread2->tid;
    }
}

sub _thread1Func {
    while (1) {
        next unless defined $thread2_tid;
        last if $thread2_tid == -1;
        my $thread2 = threads->object($thread2_tid);
        $thread2->kill('SIGUSR1');
        sleep 1;
    }
}

sub _thread2Func {
    local $SIG{'USR1'} = sub { print "SIGUSR1 received\n" };
    local $| = 1;
    while (1) {
        sleep 1;
        print '.';
        if (5 < time - $^T) {
            $thread2_tid = -1;
            last;
        }
    }
}

myfunc();
$_->join for threads->list;
于 2013-08-20T17:14:50.343 回答
1

默认情况下,perl 变量在创建线程时跨线程复制。每个线程基本上都在自己的解释器中运行(“ithreads”中的“i”)。

$thread2在范围内(感谢our),但在创建时未定义_threadFunc1。因此,新线程获得了一个$thread2未定义的副本,然后,如您所知,它致命地尝试对未定义的对象进行方法调用。

您可以$thread2在创建必须引用其初始化值的线程之前进行初始化,或者share它并协调访问。但是,鉴于您向我们展示的一小段摘录,我同意 Sinan Ünür 的观点,即重新设计可能是最好的。

于 2013-08-20T21:49:35.167 回答