Perl STDIN挂在后台,在前台工作正常

时间:2017-08-29 21:34:35

标签: perl stdin

这是我的程序

my $input;
my $finish = 0;
my $timer = 5; # 5 seconds
eval {
    while( ! $finish ) {
        local $SIG{ALRM} = sub {
          # check counter and set alarm again
          if (--$timer) { alarm 1 }
          # no more waiting
          else { die "timeout getting the input \n" }
        };
        # alarm every second
        alarm 1;
        $input = <STDIN>;
        alarm 0;
        if ( $input ) {
            chomp $input;
            if( $input ){
                print( "Received input : $input" );
                $finish = 1;
            } else {
                print( "Please enter valid input" );
            }
        } else {
            print( "input is undefined" );
            last;
        }
    }
};

if ($@ || !$input) {
    print( "Timeout in getting input." );
    return undef;
}

return $input;

STDIN在前台工作正常。但是在运行相同的程序背景时失败了。如果用户在5秒内没有输入任何输入,则逻辑是退出循环。但是当在后台运行时,该进程应在​​x秒内退出,但该进程卡在行<STDIN>中。

如何解决这个问题?

1 个答案:

答案 0 :(得分:3)

当后台进程尝试终端输入时,会发送信号SIGTTIN,其默认操作为“停止” - 即进程暂停,就像收到SIGSTOP一样。由于它已停止,因此无法处理其警报,退出或执行任何其他操作。

因此,您将要设置SIGTTIN处理程序以覆盖该默认停止行为。

您可以做的最简单的事情是local $SIG{TTIN} = 'IGNORE';,这会导致信号被忽略。然后,STDIN的读取将立即失败(返回undef并将$!设置为EIO),您将在代码中点击“输入未定义”的情况。

您还可以设置local $SIG{TTIN} = sub { die "process is backgrounded" };,以便更清楚地区分该情况。

或者您可以使用信号处理程序设置一些聪明的东西并重试读取,这样如果用户决定在超时到期之前重新连接并且他们仍然可以提供输入,但我保留了由你决定。