为什么“kill”没有立即退出线程?

问题描述 投票:0回答:2

我正在尝试编写一个简单的脚本,该脚本生成一个执行可能超时的任务的线程。 (为了为 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”信号时立即打印消息并退出?

windows multithreading perl timeout signals
2个回答
3
投票

这些“信号”不是实际的操作系统信号,并且有些操作它们不会中断

警告:该模块提供的线程信号功能实际上并不通过操作系统发送信号。它在 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
当然并不重要——但这都是一个警告,需要用实际工作仔细测试该信号旨在停止。


2
投票

信号只能发送到进程。因此,

$thread->kill('STOP')
不可能发送实际信号。因此,没有任何事情会打扰
sleep

在每个语句之间,Perl 检查是否有“信号”传入。如果有,则处理它。因此,只有在

sleep
完成后才会处理“信号”。

如果您有十次一秒睡眠而不是一次十秒睡眠,则等待时间最多为一秒。

© www.soinside.com 2019 - 2024. All rights reserved.