perl:没有按“enter”就退出

时间:2015-05-12 15:03:38

标签: multithreading perl

use threads;
use threads::shared;
use Term::ReadKey;

sub input_worker {

    local $SIG{'KILL'} = sub { threads->exit(0); return;};

    while (1) {
        if (defined(my $char = ReadKey 0, *STDIN)) {
            print "$char";
        }
    }

    return;
} ## end sub input_worker

my $in_thr = threads->create(\&input_worker);
sleep 5;
my $rc = $in_thr->kill('KILL')->join();
print "$rc\n";

这个程序不会自行退出而只是挂起。 它只会在按下“输入”后退出

我怎样才能使它在'kill'信号发出后自行退出

P.S。我不想使用detach();

1 个答案:

答案 0 :(得分:5)

混合信号和线程是一个挑战,因为$thread->kill实际上并不使用真实信号(因为信号被发送到进程,而不是线程)。这也是一样,因为如果确实如此,SIGKILL可能会破坏事物。

即使谈论'正常'信号 - 你也会有轻微的意外行为,因为perl对它们的处理请参见:perlipc。使用并非不可能,但您需要了解所涉及的警告。

但问题的根源是 - 信号是安全处理的,这意味着perl会等待一段合适的时间来处理它。在“读取”操作期间不会这样做,因此信号处理将被推迟。

我认为这里可能发生的事情是ReadKey不像您认为的那样是非阻塞操作。参考Term::ReadKey联机帮助页

  

ReadKey MODE [,Filehandle]   采用整数参数,该参数当前可以是以下值之一:

 0    Perform a normal read using getc
-1   Perform a non-blocked read
>0   Perform a timed read

所以它的作用是 - 从STDIN开始读取,并阻止(忽略信号)直到你按下回车键。此时它运行您的信号处理程序。

鉴于你在这里尝试做什么 - 我建议你根本不想使用信号,而只是使用共享变量。

这样的事情:

use threads;
use threads::shared;
use Term::ReadKey;

my $done : shared; 

sub input_worker {
    while ( not $done ) {
        if ( defined( my $char = ReadKey( -1, *STDIN ) ) ) {
            print "$char";
        }
    }
    return;
} ## end sub input_worker

my $in_thr = threads->create( \&input_worker );
sleep 10;
$done++;
my $rc = $in_thr->join();
print "$rc\n";

将在超时后终止,并且因为它正在执行非阻塞读取,它将按时保释,无需输入。你应该注意 - 这个线程将“旋转”快速循环,等待输入是否被按下 - 所以它的CPU效率不高。 (循环中的一个小延迟对那里有很大帮助,比如0.1s)。