2

我有一个 Perl 脚本,它读取命令文件并在必要时通过执行以下操作重新启动:

myscript.pl:

exec '/home/foo/bin/myscript.pl';
exit(0);

现在,这工作正常,除了一个问题。读取命令文件的线程无权访问我使用的 DBI 句柄。在多次重新启动后,我似乎建立了打开的 mysql 连接的数量,直到我得到可怕的“连接太多”错误。DBI 规范说:

“由于这个(可能是临时的)限制,新创建的线程必须自己连接到数据库。句柄不能跨线程共享。”

有什么方法可以关闭连接,或者可能是另一种重新启动脚本的方法?

4

3 回答 3

2

使用线程之间共享的标志变量。让命令行读取线程将标志设置为退出,并且持有数据库句柄的线程释放它并实际执行重新执行:

#!/usr/bin/perl

use threads;
use threads::shared;

use strict; use warnings;
my $EXIT_FLAG :shared;

my $db_thread = threads->create('do_the_db_thing');
$db_thread->detach;

while ( 1 ) {
    sleep rand 10;
    $EXIT_FLAG = 1 if 0.05 > rand or time - $^T > 20;
}

sub do_the_db_thing {
    until ( $EXIT_FLAG ) {
        warn sprintf "%d: Working with the db\n", time - $^T;
        sleep rand 5;
    }
    # $dbh->disconnect; # here
    warn "Exit flag is set ... restarting\n";
    exec 'j.pl';
}
于 2009-12-02T21:06:15.400 回答
2

您可以尝试注册一个 atexit 函数以在打开 DBI 句柄时关闭它,然后使用 fork & exec 重新启动脚本,而不是只执行 exec。然后父级将调用 exit,调用 atexit 回调来关闭 DBI 句柄。孩子可以正常重新执行自己。

编辑:再考虑几分钟后,我相信您可以完全跳过 atexit,因为在父母退出时手柄会自动关闭。当然,除非您需要在关闭数据库句柄时执行比简单的文件句柄关闭更复杂的操作。

my $pid = fork();
if (not defined $pid) {
    #Could not fork, so handle the error somehow
} elsif ($pid == 0) {
    #Child re-execs itself
    exec '/home/foo/bin/myscript.pl';
} else {
    #Parent exits
    exit(0);
}
于 2009-12-02T21:09:56.737 回答
2

如果您期望有很多连接,您可能希望DBI::Gofer充当您的 DBI 代理。您可以在任意数量的脚本中创建任意数量的连接,并且 DBI::Gofer 会尽可能地共享它们。

于 2009-12-02T23:02:58.657 回答