我正在尝试编写一个简单的脚本,该脚本会产生一个线程,该线程执行一个可能超时的任务。(为了编写一个简单的StackOverflow示例,我用sleep
命令替换了实际的进程)。
这个程序生成一个线程,然后使用cond_timedwait
来监视线程并检查它是否超时。如果发生超时,它将使用“STOP”信号调用线程上的kill
方法,以通知线程它应该退出。
use strict;
use threads;
use threads::shared;
use warnings;
my $var :shared;
my $thread = threads->create(sub {
# Tell the thread how to handle the STOP signal
local $SIG{'STOP'} = sub {
print "Stop signal received\n";
threads->exit();
};
# Perform a process that takes some time
sleep 10;
# Signal that the thread is complete
lock($var); cond_signal($var);
});
# Current time + 1 second
my $wait_time = time() + 1;
my $timeout;
{
# Wait for the thread to complete or until a timeout has occurred
lock($var); $timeout = !cond_timedwait($var, $wait_time);
}
# Check if a timeout occurred
if ($timeout) {
print "A timeout has occurred\n";
# Signal the thread to stop
$thread->kill('STOP')->join();
}
else {
$thread->join();
}
此代码成功运行并输出以下输出:
1秒过去......
A timeout has occurred
9秒过去......
Stop signal received
问题是,即使检测到超时并将“STOP”信号发送到线程,程序似乎仍在等待整整10秒,然后才打印“收到停止信号”并退出。
我试着改变它,使它在终止线程后调用detach
而不是join
,但“收到停止信号”消息从未被打印出来,这意味着程序在线程干净退出之前就退出了。我想确保线程确实被中断并退出,因为在真实的的程序中,我希望在发生超时后终止并重试进程,如果在分离的线程上已经运行了另一个示例,则该进程将无法工作。
如何使线程在收到“STOP”信号时立即打印消息并退出?
2条答案
按热度按时间hs1ihplo1#
这些“信号”并不是实际的操作系统信号,有些操作不会被它们中断
注意:此模块提供的线程信号功能实际上并不通过操作系统发送信号。它在Perl级别模拟信号,以便在适当的线程中调用信号处理程序。例如,发送
$thr->kill('STOP')
实际上并不暂停线程(或整个进程),但会导致在该线程中调用$SIG{'STOP'}
处理程序(如上所述)。...
相应地,向线程发送信号不会中断线程当前正在执行的操作:信号将在当前操作完成后起作用。例如,如果线程在I/O调用上阻塞,向其发送信号不会导致I/O调用中断,因此信号将立即起作用。
没有说明“operation”的粒度,但
sleep
显然是不可中断的,因此信号处理程序仅在其完成后运行。输出量
使用
detach
而不是join
时,它仍然会在正确的时间停止循环,但我看不到信号处理程序运行的迹象。(在我的测试中,我让信号处理程序也写一个文件,而使用detach
时,它没有。)对于我来说,使用共享变量等,一切都是一样的,就像问题中一样。当然,这个
sleep
并不重要--但它是一个警告,要仔细测试实际作业,信号的目的是停止。nwlqm0z12#
信号只能发送给进程。因此,
$thread->kill('STOP')
不可能发送一个实际的信号。因此,没有任何东西会中断sleep
。在每个语句之间,Perl检查是否有一个“信号”进入。如果有,它就处理它。所以“信号”只在
sleep
完成后才被处理。如果你有10个1秒的睡眠而不是1个10秒的睡眠,等待的时间最多是1秒。