Perl 5.10 - 除非在sleep()调用期间收到,否则忽略POSIX信号?

时间:2014-05-05 21:34:21

标签: perl unix

在涉及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信号,但只有第一个脚本响应它。第二个脚本只是继续。没有消息,没有退出,没有。

我如何纠正这种情况?

2 个答案:

答案 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代码必须仔细编写,以应对信号和安全信号"输送系统。您使用的数据库驱动程序可能没有考虑到这一点,因此无法正常工作。