我正在尝试编写一个简单的脚本,该脚本生成一个执行可能超时的任务的线程。 (为了为 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 秒,然后才打印“Stop signal returned”并退出。
我尝试更改它,以便在杀死线程后调用
detach
而不是 join
,但是永远不会打印“收到停止信号”消息,这意味着程序在线程干净退出之前退出。我想确保线程实际上被中断并退出,因为在实际程序中,我想在超时发生后终止并重试该进程,并且如果已经在分离的线程上运行另一个实例,则该进程将无法工作.
如何才能让线程在收到“STOP”信号时立即打印消息并退出?
这些“信号”不是实际的操作系统信号,并且有些操作它们不会中断
警告:该模块提供的线程信号功能实际上并不通过操作系统发送信号。它在 Perl 级别模拟信号,以便在适当的线程中调用信号处理程序。例如,发送
实际上并不挂起线程(或整个进程),但确实会导致在该线程中调用$thr->kill('STOP')
处理程序(如上所示)。$SIG{'STOP'}
...
相应地,向线程发送信号不会中断线程当前正在处理的操作:信号将在当前操作完成后起作用。例如,如果线程卡在 I/O 调用上,向其发送信号不会导致 I/O 调用中断,从而使信号立即生效。
“操作”的粒度没有说明,但
sleep
显然是不可中断的,因此信号处理程序仅在完成后运行。有不同的工作来打扰
use warnings;
use strict;
use feature 'say';
use threads;
say "Start at ", scalar localtime, " (", time, ")";
my $thread = threads->create(sub {
# Tell the thread how to handle the STOP signal
$SIG{'STOP'} = sub {
say "\tStop signal received. Exiting at ", time;
threads->exit();
};
say "\tIn the thread ", threads->tid;
# Perform a process that takes some time
#sleep 10;
do { sleep 1; say "\tnappin'... ($_ sec)" } for 1..10;
});
sleep 3;
$thread->kill('STOP')->join(); # works differently with detach()
say "Main thread done, exiting at ", time;
输出
2022 年 7 月 7 日星期四 11:11:27 开始 (1657217487) 在线程 1 中 小睡……(1 秒) 小睡……(2秒) 收到停止信号。退出 1657217490 主线程完成,在 1657217490 处退出
使用
detach
而不是 join
它仍然会在正确的时间停止该循环,但我没有看到信号处理程序运行的迹象。 (在我的测试中,我让信号处理程序也编写一个文件,但使用 detach
则不会。)对于共享变量等,这对我来说都是一样的,就像问题中一样。
这个
sleep
当然并不重要——但这都是一个警告,需要用实际工作仔细测试该信号旨在停止。
信号只能发送到进程。因此,
$thread->kill('STOP')
不可能发送实际信号。因此,没有任何事情会打扰sleep
。
在每个语句之间,Perl 检查是否有“信号”传入。如果有,则处理它。因此,只有在
sleep
完成后才会处理“信号”。
如果您有十次一秒睡眠而不是一次十秒睡眠,则等待时间最多为一秒。