有很多文件说“你应该避免使用带闹钟的睡眠,因为很多系统都会使用闹钟来实现睡眠”。实际上,我遇到了这个问题。 那么,当睡眠()无法正常使用警报时,是否有人可以帮助我,我可以做什么'睡眠'?我已经尝试了'usleep'的Time :: HiRes模块和select()函数。但它们也没有用。
答案 0 :(得分:4)
看到你被闹钟打断了,因此无法可靠地使用sleep()或select(),我建议将Time :: HiRes :: gettimeofday与select()结合使用。
这是我没有测试过的一些代码。它应该抵抗被信号中断,并且将睡眠所需的秒数加上0.1秒。如果你愿意燃烧更多的CPU周期而不做任何工作,你可以使分辨率更好:
...
alarm_resistant_sleep(5); # sleep for 5 seconds, no matter what
...
use Time::HiRes;
sub alarm_resistant_sleep {
my $end = Time::HiRes::time() + shift();
for (;;) {
my $delta = $end - Time::HiRes::time();
last if $delta <= 0;
select(undef, undef, undef, $delta);
}
}
答案 1 :(得分:1)
您可以通过system
system ( "sleep", 5 );
或者我误解了这个问题?
答案 2 :(得分:1)
您可以尝试AnyEvent
:
use AnyEvent;
my $cv = AnyEvent->condvar;
my $wait_one_and_a_half_seconds = AnyEvent->timer(
after => 1.5,
cb => sub { $cv->send }
);
# now wait till our time has come
$cv->recv;
答案 3 :(得分:1)
使用时(来自MySQL forum)
use Sys::SigAction qw( set_sig_handler );
eval {
my $hsig = set_sig_handler( 'ALRM', sub { my $canceled = 1; die; }, { mask=>[ qw( INT ALRM ) ] ,safe => 0 } );
alarm($timeout);
...
alarm(0);
}
我注意到,对sleep($delay)
$timeout
短于$delay
的所有后续调用最终都会终止脚本执行,并打印“Alarm clock
”
我找到的解决方法是再次拨打alarm()
,但值不大(3600),并立即取消该警报。
eval {
alarm(3600);
print " .... Meeeep ...."; # Some trace
alarm(0);
};
然后我可以使用sleep()
而不再受到干扰。
以下示例(实时代码段):
sub unmesswithsleep {
eval {
alarm(3600);
&tracing (8, " .... Meeeep ....");
alarm(0);
};
}
sub lockDBTables {
return (0) unless ($isdbMySQLconnect);
my $stm = qq {
LOCK TABLES
myBIGtable WRITE
};
my $timeout = 60; # This is the timer set to protect against deadlocks. Bail out then.
eval {
my $h = set_sig_handler( 'ALRM', sub { my $canceled = 1; die; }, { mask=>[ qw( INT ALRM ) ] ,safe => 0 } );
alarm($timeout);
my $res = $dbmyh->do($stm) + 0;
alarm(0); # Reset alarm
};
if ( $@ =~ m/Die/i ) {
$isdbTabledlocked = 0;
&tracerr (0, "FATAL: Lock on Tables has NOT been acquired within ${timeout}s. Lock is set to <$isdbTabledlocked>.");
&unmesswithsleep(); # MUST be called each time alarm() is used
return (0);
} else {
$isdbTabledlocked = 1;
&tracing (2, " Good: Lock on Tables has been acquired in time. Lock is set to <$isdbTabledlocked>.");
&unmesswithsleep(); # MUST be called each time alarm() is used
return (1);
}
# Can use sleep() now.
}
答案 4 :(得分:0)
尝试
print "Start\n";
select undef, undef, undef, 1;
print "End\n";
这会睡1秒钟。
答案 5 :(得分:0)
听起来你的代码会被一些设置闹钟的代码打断。这是设计使您看到预期的行为。换句话说,警报*应该总是中断睡眠呼叫。
如果您正在寻找一种纯粹的perl睡眠方式而不会被警报打断,您可以通过安装自己的警报信号处理程序来完成此操作。这样,当您的代码发出警报时,它不会中断您的处理。
但是,一个重要的警告是,这将延迟其他代码设置的任何警报。其他代码将迟到警报;代码完成后这意味着如果你想与他人合作,你最好使用其他解决方案之一。
以下是一个例子:
#!/usr/bin/perl
use POSIX;
use strict;
use warnings;
# set an alarm
print "Setting alarm\n";
alarm 1;
my $old_alarm;
my $snoozed;
{
# store the previous alarm handler (if any)
$old_alarm = $SIG{ALRM};
# override the alarm handler so that we don't
# get interrupted
local $SIG{ALRM} = sub {
print "got alarm; snoozing\n";
# record the fact that we caught an alarm so that
# we can propagate it when we're done
$snoozed++;
};
# sleep for a while.
for (1 .. 3) {
print "z" x $_ ,"\n";
sleep 1;
}
}
# replace the old sleep handler;
$SIG{ALRM} = $old_alarm
if $old_alarm;
# if we had to snooze fire an immediate alarm;
if ($snoozed) {
POSIX::raise(POSIX::SIGALRM);
}
您引用的文档提示但未描述不同的症状。当通过警报实现睡眠时,您需要担心的主要问题是当有人呼叫睡眠时重置警报。
*显然有一些版本的perl(例如:旧的Win32),其中一个警报不会中断睡眠。