Lucas Rey
Lucas Rey

Reputation: 467

How do I detect if thread/s is running

The following is a simple code example I'm working on. It just starts a thread, wait 5 seconds, and then terminate it.

#!/usr/bin/perl
use strict;
use warnings;
use threads;

sub thread_sub
 {
   threads->create(sub
    {
        sleep 5;   # HERE A WHILE ROUTINEs EMULATED BY SLEEP
        threads->detach();
    });
}

thread_sub();
exit;

But the result is:

# ./multithread.pl 
Perl exited with active threads:
        1 running and unjoined
        0 finished and unjoined
        0 running and detached

This because it runs the thread but after that exit without waiting. So, how can I wait for thread to finish before exit? I know there is is_running, but I don't known how to implement it in my code. Obliviously the reported code is just an example to understand how to implement is_running. Thank you.

Upvotes: 1

Views: 1008

Answers (2)

zdim
zdim

Reputation: 66883

Why are you doing this? Detaching a thread means that you don't care about its return or fate; it will finish and exit or be killed as the program is about to exit.

If you want to wait for it don't detach but join.


As for the question of how to use is_running, you need a thread object

use warnings;
use strict;
use feature 'say';
use threads;
$| = 1;

sub thread_sub
{
    my $thr = threads->create(sub
    {
        ## threads->detach();
        sleep 2; say "\tprocessing ..";
        sleep 2; say "\tdone";
    });
    return $thr;
}

my $thr = thread_sub();

while ($thr->is_running) {  # or: while (threads->list)
    sleep 1;
    say "main";
}

$_->join for threads->list;  # instead of detaching

say "done";

Btw, a detached thread is also covered by is_running (or list) and the above works for it as well. But doing that doesn't make sense; I am just discussing the method you ask about.

Upvotes: 1

ikegami
ikegami

Reputation: 385754

To wait for a thread to finish, one typically uses the following:

$thread->join();

To wait for all threads, one would therefore use the following:

$_->join() for threads->list();

Don't detach the thread if this is what you are going to do.


About detach...

If you had fire-and-forget threads, you could use

use threads;
use threads::shared;

my $thread_count :shared = 0;

sub thread_sub {
   { lock $thread_count; ++$thread_count; cond_signal($thread_count); }
   my $thread = async {
      sleep 5;

      { lock $thread_count; --$thread_count; cond_signal($thread_count); }
   };

   $thread->detach();  # Free the small thread object as soon as it completes.
}

thread_sub();

# When it's time to exit:
{ lock($thread_count); cond_wait($thread_count) while $thread_count != 0; }

But that doesn't gain you much over just joining the threads, which is far simpler.

use threads;

sub thread_sub {
   async {
      sleep 5;
   };
}

thread_sub();

# Periodically:
$_->join() for threads->list(threads::joinable);

# When it's time to exit:
$_->join() for threads->list();

Finally, it's more common in practice to create a pool of threads and reuse them rather then creating threads on the fly because thread creation is expensive in Perl. In this situation, detaching makes even less sense.

use threads;

use Thread::Queue qw( );  # 3.01+

use constant NUM_WORKERS => 3;

sub process_job { sleep 5 }

my $q = Thread::Queue->new();
for (1..NUM_WORKERS) {
   async {
      while (my $job = $q->dequeue()) {
         process_job($job);
      }
   };
}

$q->enqueue('some_job');

# When it's time to exit:
$q->end();
$_->join() for threads->list();

I haven't used it, but look into Thread::Pool.


By the way, async { ... } is just a cleaner way of saying threads->create(sub { ... }).

Upvotes: 5

Related Questions