【问题标题】:Perl STDIN hangs in background, works fine in foregroundPerl STDIN 在后台挂起,在前台工作正常
【发布时间】:2017-08-30 06:16:21
【问题描述】:

这是我的程序

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 秒内退出,但进程会卡在&lt;STDIN&gt; 行。

如何解决这个问题?

【问题讨论】:

  • 每个程序在放在后台时都会挂在 STDIN 上。它应该从哪里获得输入?
  • 用户应在 x 秒内输入,否则程序应退出 while 循环。由于这是在后台,用户输入是不可能的,所以程序应该在 x 秒后退出,这不会发生。
  • 我明白了。尝试 getc 并设置 tty 选项,如下所示:perldoc.perl.org/functions/getc.html
  • @yacc 有一个tostop 标志,但没有tistop 标志:)

标签: perl stdin


【解决方案1】:

当后台进程尝试终端输入时,它会收到信号SIGTTIN,它的默认操作是“停止”——即进程暂停,就像它收到SIGSTOP一样。由于它已停止,它没有机会处理它的警报、退出或做任何其他事情。

因此,您需要设置一个SIGTTIN 处理程序来覆盖该默认停止行为。

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

你也可以设置local $SIG{TTIN} = sub { die "process is backgrounded" };,这样你就可以更清楚地区分这种情况了。

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

【讨论】:

  • 读到这里,我怀念我们一直在 Unix 上的日子。 :)
  • 感谢您的详细解释。 local $SIG{TTIN} = sub { die "process is backgrounded" }; 工作 :)
  • @SrikanthJeeva 总是乐于提供帮助 :)
猜你喜欢
  • 1970-01-01
  • 2012-02-16
  • 1970-01-01
  • 2011-11-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-11-01
相关资源
最近更新 更多