How can I handle scheduling threads with dependencies in Perl? - multithreading

I have the following scenario:
sub_1 can run immediately
sub_2 can run immediately
sub_3 can run only after sub_1 finishes
sub_4 can run only after sub_1 finishes
sub_5 can run only after sub_2 finishes
sub_6 can run only after sub_2 finishes
sub_7 can run only after both sub_1 and sub_2 finish
sub_8 can run only after both sub_1 and sub_2 finish
I would like each sub to start run as soon as possible, than wait for all of them to finish.
I would really appreciate you help in creating a clean solution for this simple scenario -- I'm new to multi-threading.
I'm not sure if it makes a difference, but those subs are all in an object.

I'd suggest a "Boss/Worker" model, wherein one thread manages the subroutines to be executed in worker threads, who in turn report their status back to the boss upon completion.
In this model the boss is the only thread that needs to know how tasks are to be ordered. It might look something like this:
use threads;
use Thread::Queue;
use Thread::Pool;
our $done_queue = Thread::Queue->new;
our $work_pool = Thread::Pool->new;
sub sub_1 {
... do the work ...
$done_queue->enqueue('sub_1'); # tell the boss we're all done
}
sub sub_2 {
... do the work ...
$done_queue->enqueue('sub_2'); # tell boss we're done
}
...
# Main loop (boss thread)
$work_pool->enqueue(\&sub_1);
$work_pool->enqueue(\&sub_2);
while (my $sub_name = $done_queue->dequeue) {
# You, the boss thread, keep track of state and
# transitions however you like. You know what's
# just finished and what's finished in the past
...
}
Of course, abstraction can make that neater -- you could hide the Pool and the Queue behind a single object, one which didn't require sub_1() to know about the status queue at all:
$boss->enqueue( 'sub_1' => \&sub_1 ); # Will return 'sub_1' via await_completed()
$boss->enqueue( 'sub_2' => \&sub_2 ); # Will return 'sub_1'
while (my $sub_name = $boss->await_completed) {
...
}

Here's a possible solution using threads and thread sharing. Most of the code is just mocking up the test and emulating threads that have to do "work" before they finish. In the example the main thread spawns seven threads that each have a random amount of time that they have to do "work". The threads cannot begin working until the other threads they are dependent on (set in the dependencies array) have finished. You can change the thread dependencies and run the example a few times to illustrate that it works correctly.
Additionally you can have each thread terminate after it runs and have the main thread terminate after all of the subthreads have finished by checking the status hash.
use strict;
use warnings;
use threads;
use threads::shared;
my %status : shared;
my $dependencies = [
{3 => 1}, #three can only run after one has finished...
{4 => 1}, #four can only run after one has finished...
{5 => 2}, #five can only run after two has finished...
{6 => 1}, #etc...
{6 => 2},
{7 => 1},
{7 => 2}
];
main();
sub main{
foreach my $thread_number (1..7){
spawn_thread($thread_number);
}
while(1){
print "I am the main thread\n";
sleep(1);
}
}
sub spawn_thread{
my $thread_number = shift;
$status{$thread_number} = 'wait';
my $thr = threads->new(\&thread_routine, $thread_number);
}
sub thread_routine{
my $thread_number = shift;
my $working_time_left = int(rand(5)) + 1; #make a random time that this thread needs to "work"
while(1){
print "I am thread number $thread_number with status $status{$thread_number}\n";
{
lock(%status);
#see if this thread is active; if so, see if it finished running running
if ($status{$thread_number} eq 'active'){
if ($working_time_left <= 0){
$status{$thread_number} = 'ran';
}
}
else{
#see if we can activate
if ($status{$thread_number} eq 'wait'){
my $can_activate = 1;
foreach my $index (0..$#$dependencies){
if (exists $dependencies->[$index]->{$thread_number}){
if ($status{$dependencies->[$index]->{$thread_number}} ne 'ran'){
$can_activate = 0;
last;
}
}
}
if ($can_activate){
$status{$thread_number} = "active";
}
}
}
}
sleep(1);
if ($status{$thread_number} eq 'active'){ #do "work"
$working_time_left--;
}
}
}

Fork and create 2 processes:
In process 1:
sub_1; sub_3
In process 2:
sub_2; wait for sub_1 end; sub_4

Related

Perl set timeout within thread fails: 'Alarm clock'

I have a threaded application and would like to set timeouts for the threads. Peldoc for alarm suggests to use a eval-die pair and catch the ALRM signal. However, this fails with threads producing the error Alarm clock:
use strict; use warnings;
require threads;
require threads::shared;
my $t = threads->create( sub {
eval {
$SIG{ALRM} = sub { die "alarm\n" };
alarm 2;
main();
alarm 0;
};
if ($#){
die $# unless $# eq "alarm\n";
print "timed out\n";
}
}
);
my #r = $t->join;
print "done\n";
sub main {
sleep 3;
}
This post suggests that alarm is called without signal handler in the threads library. Another post is about this problem and answers suggest to use fork and waitpid, but I would really like to use threads. Another post claims to come up with a solution, but this still gives the Alarm clock error for me. I tried to catch Alarm clock in the if ($#), but no success. Any idea how I could make this work?
The whole idea of using alarm in threads is problematic.
Signals are sent to processes, not threads.
What if two threads want to use alarm?
You'll have to implement your own system. The following is an attempt at a general solution:
package Threads::Alarm;
use strict;
use warnings;
use threads;
use threads::shared;
use Exporter qw( import );
our #EXPORT_OK = qw( alarm thread_alarm );
# A list of "$time:$tid" strings sorted by ascending time.
my #alarms :shared;
sub thread_alarm {
my ($wait) = #_;
my $tid = threads->tid();
lock #alarms;
# Cancel existing alarm for this thread, if any.
for my $i (0..$#alarms) {
if ((split(/:/, $alarms[$i]))[1] == $tid) {
splice(#alarms, $i, 1);
last;
}
}
# Create an alarm
if ($wait) {
my $when = time() + $wait;
# A binary search would be better.
my $i;
for ($i=0; $i<#alarms; ++$i) {
last if $when < (split(/:/, $alarms[$i]))[0];
}
splice(#alarms, $i, 0, "$when:$tid");
}
# Notify others of change to #alarms.
cond_broadcast(#alarms);
}
{
no warnings 'once';
*alarm = \&thread_alarm;
}
threads->create(sub {
while (1) {
my $thread;
{
lock #alarms;
while (1) {
# Wait for an alarm request to come in.
cond_wait(#alarms) while !#alarms;
# Grab the soonest alarm.
my ($when, $tid) = split(/:/, $alarms[0]);
# Check if the thread still exists.
my $thread = threads->object($tid)
or last;
# Wait for the #alarms to change or for the alarm time.
last if !cond_timedwait(#alarms, $when);
}
# Before releasing the lock, remove the alarm we're about to raise.
shift(#alarms);
# Notify others of change to #alarms.
# Doesn't actually do anything at this time.
cond_broadcast(#alarms);
}
$thread->kill('ALRM') if $thread;
}
})->detach();
1;
Completely untested. Well, I made sure it compiles, but that's it.
Note that threads->kill doesn't send a real signal (since those are sent to processes, not threads), so the OS won't interrupt any operation (e.g. sleep, wait). Simple solution: Send a real signal to a handler that does nothing right after calling threads->kill. Maybe I should have written a solution that was based around the actual SIGALRM.

perl threads: is_joinable vs is_running

while ($thr->is_running() {
# do something
}
vs
while (! $thr->joinable()) {
# do something
}
Is there any difference between the two?
When would a programmer use one over the other and vice versa?
I am assuming you cant join a thread if it's running so arent they basically the same thing?
If so, why does perl provides two different ways to check the status of a thread?
is_joinable is not the same as !is_running.
is_joinable checks for
(thread->state & PERL_ITHR_FINISHED) &&
!(thread->state & PERL_ITHR_DETACHED) &&
!(thread->state & PERL_ITHR_JOINED)
is_running checks for
!(thread->state & PERL_ITHR_FINISHED)
So
A detached thread that finished is neither running nor joinable.
A thread that's already been joined is neither running nor joinable.
As per the documentation :
$thr->is_running()
Returns true if a thread is still running
(i.e., if its entry point function has not yet finished or exited).
$thr->is_joinable()
Returns true if the thread has finished running,
is not detached and has not yet been joined. In other words,
the thread is ready to be joined, and a call to $thr->join() will not block.
So the difference stems from the way detached threads are treated.
i.e $thread->is_running() would return true if the thread is running irrespective of whether it is detached or not
but "not $thread->is_joinable()" would return true even if a thread is detached but has stopped running.
Example:
1) detached thread
use strict;
use warnings;
use threads;
sub do_nothing {
print("in thread\n");
sleep(30);
return;
}
my $t = threads->create(\&do_nothing);
$t->detach();
while ($t->is_running()) {
print("is running\n");
sleep(4);
}
if ($t->is_joinable()) {
print("is joinable\n");
}
else {
print("not joinable\n");
}
exit;
Exampled : a non-detached thread
use strict;
use warnings;
use threads;
sub do_nothing {
print("in thread\n");
sleep(30);
return;
}
my $t = threads->create(\&do_nothing);
while ($t->is_running()) {
print("is running\n");
sleep(4);
}
if ($t->is_joinable()) {
print("is joinable\n");
}
else {
print("not joinable\n");
}
exit;
They are not the same.
A thread is "joinable" if it has not been joined or detached, and is no longer running. That is to say, it provides a poll interface to the condition that joining the thread would block on.
Finished running, not yet joined, not detached == joinable
Not yet finished running, not yet joined, not detached == running.
See Perl Threads.

Perl async tasks for "any" code, no matter what it is?

I've been writing a "checker" system that performs various "checks" on various services, systems, databases, files, etc. A "check" is generic in nature and can be anything. All checks are reported in a common format weather they pass or fail, whatever that may be.
It is written in a modular OO fashion so that developers can simply follow the framework and write checks independently of one and other. Each object contains a shared reporting object which after they run a check they simply $self->{'reporting'}->report(params). The params are defined and developers are assumed to report appropriately. The reporting object then indexes these reports. My main loader script has entries such as the following:
my $reportingObject = new Checks::Reporting(params);
my #checks;
push #checks, new Checks::Check_One($reportingObject, params));
push #checks, new Checks::Check_One($reportingObject, params));
.
.
push #checks, new Checks::Check_N($reportingObject, params));
To kick off the checks and finalize the report once they are done I have been doing:
foreach my $check (#checks) {
$check->run_stuff();
}
$reportingObject->finalize_report();
Now since these checks are totally independent (do not worry about the reporting object) they can be run in parallel. As an improvement I have done:
my #threads;
foreach my $check (#checks) {
push #threads, async { $check->run_stuff(); }
}
foreach my $thread (#threads) {
$thread->join;
}
#All threads are complete, and thus all checks are done
$reportingObject->finalize_report();
As I said earlier the developers will write Checks independently of each other. Some checks are simple and others are not. The simple checks may not have asynchronous code in them, but others might need to run asynchronously internally such as
sub do_check {
my #threads;
my #list = #{$self->{'list'}};
foreach my $item (#list) {
push #threads, async {
#do_work_on_$item
#return 1 or 0 for success or fail
};
foreach my $thread (#threads) {
my $res = $thread->join;
if($res == 1) {
$self->{'reporting'}->report(params_here);
}
}
}
}
As you can see the threading model allows me to do things in very vague terms. Each "Check" no matter what it is runs independently in its own thread. If an individual developer has asynchronous stuff to do, no matter what it is, he simply does it independently in its own thread. I want a model similar to this.
Unfortunately threads are slow and inefficient. All of the async libraries have specific watchers such as IO, etc. I do not want anything specific. I would like an event based model that allows me to simply kick off async tasks, no matter what they are, and simply notify when they are all done so I can move on.
Hopefully that explains it and you can point me in the right direction.
This seems like a good fit for a boss-worker model:
Spawn a few workers at the beginning of the program. Make sure they all have access to a queue.
Enqueue as many checks as you like. The workers dequeue the checks, execute them, and enqueue the result in an output queue.
Your main thread looks at the results from the output thread, and does whatever it wants.
Join the workers in an END block
You probably want to look at Thread::Queue::Any if there is a chance you want to put coderefs into the queue.
Here is a fully runnable example:
use strict; use feature 'say';
use threads; use threads::shared; use Thread::Queue::Any;
use constant NUM_THREADS => 5;
local $Storable::Deparse = 1; local $Storable::Eval = 1; # needed to serialize code
my $check_q = Thread::Queue::Any->new;
my $result_q = Thread::Queue::Any->new;
# start the workers
{
my $running :shared = NUM_THREADS;
my #threads = map threads->new(\&worker, $check_q, $result_q, \$running), 1..NUM_THREADS;
END { $_->join for #threads }
}
# enqueue the checks
$check_q->enqueue($_) for sub {1}, sub{2}, sub{"hi"}, sub{ die };
$check_q->enqueue(undef) for 1..NUM_THREADS; # end the queue
while(defined( my $result = $result_q->dequeue )) {
report($$result);
}
sub report {
say shift // "FAILED";
}
sub worker {
my ($in, $out, $running_ref) = #_;
while (defined( my $check = $in->dequeue )) {
my $result = eval { $check->() };
$out->enqueue(\$result);
}
# last thread closes the door
lock $$running_ref;
--$$running_ref || $out->enqueue(undef);
}
This prints
1
2
hi
FAILED
in a slightly random order.

How to implement semaphore thread communication in Perl?

My Perl script needs to run multiple threads simultaneously...
use threads ('yield', 'exit' => 'threads_only');
use threads::shared;
use strict;
use warnings;
no warnings 'threads';
use LWP::UserAgent;
use HTTP::Request;
use HTTP::Async;
use ...
...and such threads need to obtain some information from web, so HTTP::Async is used.
my $request = HTTP::Request->new;
$request->protocol('HTTP/1.1');
$request->method('GET');
$request->header('User-Agent' => '...');
my $async = HTTP::Async->new( slots => 100,
timeout => REQUEST_TIMEOUT,
max_request_time => REQUEST_TIMEOUT );
But some threads need to access web only when other thread(s) says so.
my $start = [Time::HiRes::gettimeofday()];
my #threads = ();
foreach ... {
$thread = threads->create(
sub {
local $SIG{KILL} = sub { threads->exit };
my $url = shift;
if ($url ... ) {
# wait for "go" signal from other threads
}
my ($response, $data);
$request->url($url);
$data = '';
$async->add($request);
while ($response = $async->wait_for_next_response) {
threads->yield();
$data .= $response->as_string;
}
if ($data ... ) {
# send "go" signal to waiting threads
}
}
}, $_);
if (defined $thread) {
$thread->detach;
push (#threads, $thread);
}
}
There might be one or more threads waiting for "go" signal and there might be one or more threads that such "go" signal can send. At the beginning the status of semaphore is "wait" and once it turns to "go", it will stay so.
Finally, app checks max running time. If threads are running too long, self-termination signal is sent.
my $running;
do {
$running = 0;
foreach my $thread (#threads) {
$running++ if $thread->is_running();
}
threads->yield();
} until (($running == 0) ||
(Time::HiRes::tv_interval($start) > MAX_RUN_TIME));
$running = 0;
foreach my $thread (#threads) {
if ($thread->is_running()) {
$thread->kill('KILL');
$running++;
}
}
threads->yield();
Now to the point. My questions are:
How can I most effectively code waiting "semaphore" in the script (see comments in script above). Should I simply use just shared variable with some dummy sleep loop?
Do I need to add some sleep loop at the end of app to give time to threads for self-destruction?
You might look at Thread::Queue to perform this work. You could setup a queue that would handle the signaling between the threads waiting for the 'go' signal and the threads sending the 'go' signal. Here's a quick mock-up that I haven't tested:
...
use Thread::Queue;
...
# In main body
my $q = Thread::Queue->new();
...
$thread = threads->create(
sub {
local $SIG{KILL} = sub { threads->exit };
my $url = shift;
if ($url ... ) {
# wait for "go" signal from other threads
my $mesg = $q->dequeue();
# you could put in some termination code if the $mesg isn't 'go'
if ($mesg ne 'go') { ... }
}
...
if ($data ... ) {
# send "go" signal to waiting threads
$q->enqueue('go');
}
}
}, $_);
...
The threads that need to wait for a 'go' signal will wait on the dequeue method until something enters the queue. Once a message enters the queue one thread and only one thread will grab the message and process it.
If you wish to stop the threads so that they won't run, you can insert a stop message to the head of the queue.
$q->insert(0, 'stop') foreach (#threads);
There are examples in Thread::Queue and threads CPAN distributions that show this in more detail.
In response to your second question, the answer is, unfortunately, it depends. When you proceed to terminate your threads, what kind of clean up is required for a clean shutdown? What's the worst case scenario that could occur if the rug was yanked out from beneath the thread? You would want to plan in any time for the clean up to occur. The other option you could do is wait on each thread to actually complete.
The reason for my comment asking if you could remove the detach call is because this method allows the main thread to exit and not care what was happening to any child threads. Instead, if you remove this call, and add:
$_->join() foreach threads->list();
to the end of your main block, this will require the main application to wait for each thread to actually complete.
If you leave the detach method in place, then you will need to sleep at the end of your code if you require your threads to perform any sort of clean-up. When you call detach on a thread, what you are telling Perl is that you don't care what the thread is doing when your main thread exits. If the main thread exits and there are threads that still running that have been detached, then the program will finish with no warnings. However, if you don't require any clean-up, and you still call detach, feel free to exit whenever you like.
Try out something like this....
#!/usr/bin/perl
use threads;
use threads::shared;
$|=1;
my ($global):shared;
my (#threads);
push(#threads, threads->new(\&mySub,1));
push(#threads, threads->new(\&mySub,2));
push(#threads, threads->new(\&mySub,3));
$i = 0;
foreach my $myThread(#threads)
{
my #ReturnData = $myTread->join ;
print "Thread $i returned: #ReturnData\n";
$i++;
}
sub mySub
{
my ($threadID) = #_;
for(0..1000)
{
$global++;
print "Thread ID: $threadID >> $_ >> GLB: $global\n";
sleep(1);
}
return( $id );
}

Perl threads with alarm

Is there any way to get alarm (or some other timeout mechanism) working in perl (>=5.012) threads?
Run alarm in your main thread, with a signal handler that signals your active threads.
use threads;
$t1 = threads->create( \&thread_that_might_hang );
$t2 = threads->create( \&thread_that_might_hang );
$SIG{ALRM} = sub {
if ($t1->is_running) { $t1->kill('ALRM'); }
if ($t2->is_running) { $t2->kill('ALRM'); }
};
alarm 60;
# $t1->join; $t2->join;
sleep 1 until $t1->is_joinable; $t1->join;
sleep 1 until $t2->is_joinable; $t2->join;
...
sub thread_that_might_hang {
$SIG{ALRM} = sub {
print threads->self->tid(), " got SIGALRM. Good bye.\n";
threads->exit(1);
};
... do something that might hang ...
}
If you need different alarms for each thread, look into a module that allows you to set multiple alarms like Alarm::Concurrent.
Edit: commentors point out threads::join interferes with SIGALRM, so you may need to test $thr->is_joinable rather than calling $thr->join

Resources