我有一个Perl脚本,它读取命令文件并在必要时通过执行以下操作重新启动:
myscript.pl:
exec '/home/foo/bin/myscript.pl';
exit(0);
现在,除了一个问题,这个工作正常。读取命令文件的线程无法访问我使用的DBI句柄。经过多次重启,我似乎建立了开放的mysql连接数,直到我遇到可怕的“Too Many Connections”错误。 DBI规范说:
“由于这个(可能是临时的)限制,新创建的线程必须与数据库建立自己的连接。不能跨线程共享句柄。”
是否可以通过任何方式关闭连接或以其他方式重新启动脚本?
答案 0 :(得分:2)
使用线程之间共享的标志变量。让命令行读取线程将标志设置为退出,持有DB句柄的线程释放它并实际执行重新执行:
#!/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';
}
答案 1 :(得分:2)
您可以尝试注册atexit函数以在打开它时关闭DBI句柄,然后使用fork& exec重启脚本而不是exec。然后父进程调用exit,调用atexit回调来关闭DBI句柄。孩子可以正常地重新执行。
编辑:在考虑了几分钟之后,我相信你可以完全跳过atexit因为句柄会在父母退出时自动关闭。当然,除非在关闭DB句柄时需要执行比简单文件句柄关闭更复杂的操作。
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);
}
答案 2 :(得分:2)
如果您期望有很多连接,您可能希望DBI::Gofer充当您的DBI代理。您可以在任意数量的脚本中创建任意数量的连接,DBI :: Gofer会尽可能地共享它们。