在涉及Perl如何处理POSIX信号时,我遇到了一些问题。也就是说,除非在致电sleep()
期间收到信号,否则Perl似乎会忽略这些信号。
例如,以下代码可以正常工作:
#/usr/bin/perl
$SIG{PIPE} = sub { print STDERR "WARNING: Received SIGPIPE"; exit(1); };
while (1) { print "Waiting on signal...\n"; sleep(10); }
在从Oracle数据库读取的另一个脚本中使用上面的SIGPIPE处理程序时,子程序似乎永远不会被调用。
#/usr/bin/perl
use DBI;
$SIG{PIPE} = sub { print STDERR "WARNING: Received SIGPIPE"; exit(1); };
my $db = "redacted";
my $user = "redacted";
my $pass = "redacted";
my $table = "redacted";
my $ora = DBI->connect("dbi:Oracle:" . $db, $user, $pass);
my $sql = "SELECT * FROM " . $table;
my $query = $ora->prepare($sql);
$query->execute();
while (my @row = $query->fetchrow_array()) {
print(join('|', @row) . "\n");
}
if ( $DBI::err ) { print STDERR "ERROR: Unload terminated due to error"; }
我以相同的方式(kill -sPIPE pid
)向两个脚本发送SIGPIPE信号,但只有第一个脚本响应它。第二个脚本只是继续。没有消息,没有退出,没有。
我如何纠正这种情况?
答案 0 :(得分:1)
在DBI调用之前设置信号处理程序会导致在调用某些DBI方法后忽略它。解决方案是将信号处理程序子例程移到处理循环之前,但是在执行调用之后:
#/usr/bin/perl
use DBI;
# SIGPIPE handler used to be here
my $db = "redacted";
my $user = "redacted";
my $pass = "redacted";
my $table = "redacted";
my $ora = DBI->connect("dbi:Oracle:" . $db, $user, $pass);
my $sql = "SELECT * FROM " . $table;
my $query = $ora->prepare($sql);
$query->execute();
$SIG{PIPE} = sub { print STDERR "WARNING: Received SIGPIPE"; exit(1); };
while (my @row = $query->fetchrow_array()) {
print(join('|', @row) . "\n");
}
if ( $DBI::err ) { print STDERR "ERROR: Unload terminated due to error"; }
我不确定为什么它会解决这个问题,但确实如此。
答案 1 :(得分:0)
用于与数据库通信的DBI驱动程序很可能是用XS代码编写的。长时间阻塞的XS代码必须仔细编写,以应对信号和安全信号"输送系统。您使用的数据库驱动程序可能没有考虑到这一点,因此无法正常工作。