【问题标题】:Threads in Perl: order of detach()Perl 中的线程:detach() 的顺序
【发布时间】:2017-07-01 17:05:27
【问题描述】:

我正在尝试了解 Perl 对线程的使用。阅读documentation我遇到了以下代码:

use threads;

my $thr = threads->create(\&sub1);   # Spawn the thread
$thr->detach();   # Now we officially don't care any more

sleep(15);        # Let thread run for awhile

sub sub1 {
    my $count = 0;
    while (1) {
        $count++;
        print("\$count is $count\n");
        sleep(1);
    }
}

目标似乎是创建一个运行 sub1 15 秒的线程,同时打印一些字符串。但是,我认为我不明白程序结束时发生了什么。

首先detach()定义如下:

一旦线程被分离,它将一直运行直到完成;然后是 Perl 之后会自动清理。

但是,子程序何时结束? while(1) 永远不会结束。我也没有在sleep() 中找到任何会导致循环中断的信息。最重要的是,从我们分离的那一刻起,我们“等待脚本完成然后清理它”15 秒,所以如果我们 等待 子例程完成,为什么我们要在主脚本中需要sleep()?这个位置对我来说很尴尬;它表明主程序休眠 15 秒。但这有什么意义呢?主程序(线程?)休眠,子线程继续运行,那么子程序又是如何终止的呢?

我想这个想法是在sleep-ing 完成后,子程序结束,之后我们可以分离/清理。但是这在语法上是如何清晰的呢?在 sleep 的定义中,sleep 终止了一个子程序(以及为什么),如果有多个线程,它如何知道要终止哪个?

【问题讨论】:

    标签: multithreading perl sleep


    【解决方案1】:

    程序结束时所有线程都结束。程序在主线程结束时结束。主线程中的sleep 只是让程序运行一小段时间,之后主线程(因此程序,因此所有创建的线程)也结束。

    那么detach 是怎么回事?它只是说“我永远不会费心加入这个线程,我不在乎它返回什么”。如果你没有detach 一个线程或join 给它,程序结束时你会收到一个警告。

    【讨论】:

    • 等等,所以即使子程序还在运行,主程序也会结束?
    • 是的。这就是为什么你一开始就不想detach 一个线程。
    • 相反,您应该使用join() 来等待它完成,对吗?
    • 如果你想确保一个线程完成它正在做的事情,那么你必须join 给它(这意味着你不能分离它)。示例代码显示了分离线程的优点 - 只要进程持续存在,后台处理就应该继续进行,但可以随时安全地中断。
    • 我断言这种情况很少见 - 至少在发出干净退出信号然后加入的努力是微不足道的。 perl 线程不太适合短期快速生成线程
    【解决方案2】:

    detach 线程意味着“我不再关心”,这实际上意味着当您的进程退出时,线程将出错并终止。

    实际上-我认为您不想在 perl 中分离线程-只需在代码末尾添加join,这样它就可以干净地退出,并通过信号量或Thread::Queue 发出信号为了终止。

    $_ -> join for threads -> list; 
    

    会成功的。

    那个代码示例——在我看来——是一个不好的例子。这对sleep 来说简直是一团糟,因此一个分离的线程有机会完成,而您只需join 并且知道它已经完成。对于perl 线程尤其如此,假设它们是轻量级的,因此可以轻松启动(和detached)。如果你产生的数量足够多,以至于joining 它们的开销太高,那么你使用的 perl 线程是错误的,可能应该使用fork。

    你说的很对——线程永远不会终止,所以你的代码总是有一个“脏”的出口。

    所以我会改写:

    #!/usr/bin/perl
    
    use strict;
    use warnings;
    use threads;
    use threads::shared;
    
    my $run : shared;
    $run = 1;
    
    sub sub1 {
       my $count = 0;
       while ($run) {
          $count++;
          print("\$count is $count\n");
          sleep(1);
       }
       print "Terminating\n";
    }
    
    
    my $thr = threads->create( \&sub1 );    # Spawn the thread
    
    sleep(15);                               # Let thread run for awhile
    $run = 0;
    $thr->join;
    

    这样,您的主线程会向线程发出信号说“我完成了”并等待它完成当前循环。

    【讨论】:

    • 只是为了确保我理解加入。它被表示为一种可以“监视”与主线程分开的线程的方法。这是否意味着您可以在 sleep 行之前编写 joi 行,从而产生相同的行为?还是加入阻塞了主程序?另外,如果线程在调用join 之前完成怎么办?它会导致错误吗?返回值是否丢失? (如果问题太宽泛,请告诉我,然后我会创建一个新问题。)
    • join 是一个阻塞调用。它会等到线程完成。如果线程首先完成,那很好 - join 只是收获它并获取返回码(很像 waitpid 所做的)
    • 好的,谢谢,那么第二个问题呢? 如果线程在调用 join 之前完成怎么办?它会导致错误吗?返回值是否丢失?
    • 没有错误,没有返回值丢失。它工作得很好——所以你可以把$run = 0 行放在sleep 行之前,一切都很好。 (只是因为线程提前终止而执行的“打印”语句较少)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-03-27
    • 1970-01-01
    • 2014-06-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多