Reputation: 467
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
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
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