Perl STDIN 在后台挂起,在前台工作正常
Perl STDIN hangs in background, works fine in foreground
这是我的程序
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>
中。
如何解决这个问题?
当后台进程尝试终端输入时,它会收到信号 SIGTTIN
,其默认操作为 "stop" — 即进程暂停,就好像它收到了 SIGSTOP
。由于它已停止,因此它没有机会处理其警报、退出或执行任何其他操作。
因此,您需要设置一个 SIGTTIN
处理程序来覆盖该默认停止行为。
您可以做的最简单的事情是 local $SIG{TTIN} = 'IGNORE';
,这会导致信号被忽略。 STDIN
的读取将立即失败(returns undef,$!
设置为 EIO
),并且您会在代码中遇到 "input is undefined" 情况。
你也可以设置local $SIG{TTIN} = sub { die "process is backgrounded" };
这样可以更清楚的区分这种情况
或者你可以用信号处理程序设置一些聪明的东西并重试读取,这样如果用户决定在超时到期之前返回后台并重新连接,他们仍然能够提供输入,但我交给你吧。
这是我的程序
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>
中。
如何解决这个问题?
当后台进程尝试终端输入时,它会收到信号 SIGTTIN
,其默认操作为 "stop" — 即进程暂停,就好像它收到了 SIGSTOP
。由于它已停止,因此它没有机会处理其警报、退出或执行任何其他操作。
因此,您需要设置一个 SIGTTIN
处理程序来覆盖该默认停止行为。
您可以做的最简单的事情是 local $SIG{TTIN} = 'IGNORE';
,这会导致信号被忽略。 STDIN
的读取将立即失败(returns undef,$!
设置为 EIO
),并且您会在代码中遇到 "input is undefined" 情况。
你也可以设置local $SIG{TTIN} = sub { die "process is backgrounded" };
这样可以更清楚的区分这种情况
或者你可以用信号处理程序设置一些聪明的东西并重试读取,这样如果用户决定在超时到期之前返回后台并重新连接,他们仍然能够提供输入,但我交给你吧。