Beefy Boxes and Bandwidth Generously Provided by pair Networks
P is for Practical
 
PerlMonks  

Restarting Threads

by Helter (Chaplain)
on Apr 24, 2006 at 14:24 UTC ( [id://545287]=perlquestion: print w/replies, xml ) Need Help??

Helter has asked for the wisdom of the Perl Monks concerning the following question:

This is a complicated question, in a large environment so bear with me. :)

I work on a large project that mixes 5 languages in a single executable. The front end interface uses Perl parsing to do all the user input.
Our project requires save-restore functionality. The users will be able to provide functions that get called and need to run over time.

For example the user may write something like this:
sub doMyThing() { doStuff; waitFor( condition); doMoreStuff; }
The function doMyThing gets spawned as a thread that will pause/yield when the waitFor() function is hit.

The problem is when we do a system wide save() when the waitFor() is going. I'm trying to figure out a way that we can then later restore() and continue processing.

We can provide a function to the users that hides some "magic" in there that we may be able to use to provide this functionality, but I'm unsure the best way to do this.

I have given this some thought, we would like to make the interface to the users as simple as possible while leaving as much power in the users hands.

One way to make the users use some sort of wrapper functions, which we would like to avoid if possible, so we can later skip back to the waiting:
sub doMyThing() { waitWrapper( condition) { doStuff; } waitFor( condition); doMoreStuff; }
Then we use some sort of variables to determine which waits we have hit and where we can jump back to after the restore().

Edit: I was informed that save() restore() is not a common concept.
In running our simulations we need the ability to simulate to a point and save the state of the run. This includes all variables and state. Then later we can jump to that point without spending the time computing the state.
This saves us hours of time when debugging a problem and is an essential tool for us.
EndEdit
I'm looking for any other thoughts on this.
Rich

Replies are listed 'Best First'.
Re: Restarting Threads
by zentara (Archbishop) on Apr 24, 2006 at 16:26 UTC
    It seems to me that what you want to do is possible, you just need to work out the details, but you didn't say what language your threads are in. I'll assume it's Perl.

    I'm used to using the "sleeping thread concept" with shared variables. I've posted numerous examples of it here, just SuperSearch for Tk threads. Anyways, the basic concept is to make worker threads and put them in a while loop where they sleep, and wake up at a specified interval, and check a shared variable, to wake up and go. If it wakes up, it reads another shared variable, which would contain the code block you want it to run. THEN :-) , while it's running it's code, it checks it's shared variable to see whether it should go back to sleep( that would trigger your Save routine). The main thread could then save all the data in the thread's shared variable to some hash or db, then you could restore it later.

    It all seems doable, but the devil is in the details....making sure all the threads have properly defined shared variables, and setting up a scheme in the main thread to read the shared variables, Having an Event loop system in the main thread is pretty much essential, unless you are very clever to setup a complex while loop in the main thread.

    Here is the basis of a sleeping thread.

    foreach my $dthread(1..$numworkers){ share ($shash{$dthread}{'go'}); share ($shash{$dthread}{'data'}); share ($shash{$dthread}{'pid'}); share ($shash{$dthread}{'die'}); $shash{$dthread}{'go'} = 0; $shash{$dthread}{'data'} = $data; $shash{$dthread}{'pid'} = -1; $shash{$dthread}{'die'} = 0; $hash{$dthread}{'thread'} = threads->new(\&work,$dthread); } sub work{ my $dthread = shift; $|++; while(1){ if($shash{$dthread}{'die'} == 1){ goto END }; if ( $shash{$dthread}{'go'} == 1 ){ eval( system( $shash{$dthread}{'data'} ) ); foreach my $num (1..100){ $shash{$dthread}{'progress'} = $num; print "\t" x $dthread,"$dthread->$num\n"; select(undef,undef,undef, .5); if($shash{$dthread}{'go'} == 0){last} if($shash{$dthread}{'die'} == 1){ goto END }; } $shash{$dthread}{'go'} = 0; #turn off self before returning }else { sleep 1 } } END: }

    There is a way to use filehandles across threads too, which may be handy to use instead of shared variables.

    #!/usr/bin/perl use warnings; use strict; use threads; use threads::shared; # original idea from BrowserUK at # http://perlmonks.org?node_id=493754 for my $file ( map{ glob $_ } @ARGV ) { open my $fh, '<', $file or warn "$file : $!" and next; printf "From main: %s", scalar <$fh> for 1 .. 10; printf "Fileno:%d\n", fileno $fh; threads->create( \&thread, fileno( $fh ) )->detach; printf 'paused:';<STDIN>; } sub thread{ my( $fileno ) = @_; open my $fh, "<&=$fileno" or warn $! and die; printf "%d:%s", threads->self->tid, $_ while defined( $_ = <$fh> ); close $fh; }

    I'm not really a human, but I play one on earth. flash japh
      I think this is where after a lot of time I may have gone, and shows examples of how it could be done.

      Indeed it is native Perl threads that are being used. I will have to see if this fits into our framework.

      Thanks!
Re: Restarting Threads
by BrowserUk (Patriarch) on Apr 24, 2006 at 17:02 UTC
    I was informed that save() restore() is not a common concept.... In running our simulations we need the ability to simulate to a point and save the state of the run.

    Are you talking about:

    • a continuation type of functionality, whereby you obtain a handle to the current state of execution at some point(s) within the execution of a given run, and can then return to that snapshoted state at some later point(s) within that same run.

    Or

    • A java-style hibernate facility whereby a snapshot of the thread is saved to disk and can be restored in a completely different run of the program at a later date?

    To my knowledge, neither is currently available for ithreads, but (at least in an off-the-top-of-my-head, completely speculative theory), both might be possible. Either would be a considerable amount of work.

    My basic idea is to use demerphq's Data::Dumper::Streamer module with it's ability to serialise datastructures (including (some?) coderefs), to disk and restore them; and apply it to the thread's defstash (You'll need to search for that term manually).

    I've no idea if this is actually possible, or what the results would be if you attempted to restore the default stash without all of Perl's internal stacks etc., but it might be fun to explore the possibilities.

    Update: On Win32, the fork emulation effectively clones a thread, state, run context et al. If this is your target platform, that might also form the basis of an attack. If you forked the thread and left the clone suspended--you could resume it at a later point.


    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    Lingua non convalesco, consenesco et abolesco. -- Rule 1 has a caveat! -- Who broke the cabal?
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.
      Of the choices the java-style hibernate is what we do. For example if we have a long sequence we do every run we will run that sequence once, save and then use the snapshot to get to the "good/interesting" verification faster.

      Target platform is Linux so your last point goes away :-(

      Just to clarify (with only a few minutes of reading...much more to do), your thought is to use the Streamer module to stream the run of the thread as it goes, then when we do a restore() grab the previous state...Interesting.
      Again, much more to read, but is there a defstash for the top level thread, or are Perl threads not done that way?

      Off to read some! Thanks!

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://545287]
Approved by McDarren
Front-paged by RollyGuy
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others lurking in the Monastery: (7)
As of 2024-04-23 10:39 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found