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

Hello, I have just signed up to the site and I am also very new to perl but very interested. My question is how to run a loop in the background of my main program... I personaly want to play songs in a playlist (one starts after the other is done) while I goto(); another part of my program while maintaining the loop. (i am using Win32::MediaPlayer to play the music) here is my code (sub program that gets required into my main code):

while (($music_playlist_line_number, $music_file) = each(%AllFiles)){ $winmm = new Win32::MediaPlayer; $winmm->load("User Files\\$name\\Pro Playlist\\$music_file"); $winmm->play; $winmm->volume($volume); $song_length_micro = $winmm->length; $song_length = ($song_length_micro * .001) + .05; ### + .05 second buffer between songs; $song_pos_micro = $winmm->pos; sleep ($song_length); }

now, this code works for me however im not able to go somwhere in my program while it keeps going to different songs after Im there. I can do it with single songs, they will keep playing but I would need to run this in some kind of background process for it to keep working, independent on the main program but able to use the main programs variables and hashes I use to make it work.

Replies are listed 'Best First'.
Re: Looping in the background of your main program
by almut (Canon) on Dec 30, 2009 at 17:22 UTC

    If I'm understanding you correctly, you want to execute some code outside of the loop while the songs are playing.  As the playing itself already appears to happen in the background, the most simple approach would be to call some other routine in your program every time you get around to calling sleep at the end of the loop, and when that routine returns, just sleep for the remaining time only (i.e. song length minus time the routine took). That would mean your other code executes synchronously with the loop iterations, so a single call of the routine may not take more time than the length of the current song allows. — In other words, make that while loop the main loop of your program and arrange the other code around it.

    If you need asynchronous execution, you could use threads or fork a separate process. Which technique to use depends on a number of factors, for example how you want to share data. The latter is somewhat simpler with threads, because different processes (as created with fork) would require interprocess communication (IPC), such as pipes, sockets and signals, to explicitly exchange information.

      thanks for your reply almut, I beleive forking would be my number one choice here, however I have been looking online and reading but still do not understand how to fork a process and use my variables from my main process there aswell, if anyone can explain this to me it would be great. thank you.
        but still do not understand how to fork a process and use my variables from my main process there aswell

        The point is, you can't (directly). At the time of forking, all program data (including variables with their current values) are being duplicated, but from that point onwards, updates to the two copies of the variables do happen independently.  It's for that reason that you'd then need IPC.

        With threads and threads::shared, OTOH, you can tell Perl which variables you want to share across the different threads.  But threads may be problematic in other ways, for example in that code (which you've loaded before creating a new thread) needs to be thread-safe — which in particular external libraries (as often needed with XS modules) sometimes aren't.

        Perl threads are a big and rather cludgy hammer, and should only be used when you need to share lots of data between many processes. They're great to have when you truly need them, but in your case, you don't truly need them. :)

        Since you know exactly how long you want to wait, you can simply use the alarm function. You've got high precision for your timing, so you should probably use the Time::HiRes module, which is almost certainly a core module for you. To get all of this to work, a skeleton of your code might look like this:

        use Time::HiRes qw(alarm); # Pre-declare any variables you'll need in play_func and in # the main code my %all_files; sub play_func { ## Most of your originally posted code goes here, but ## replace the call to sleep with this: alarm ($song_length); } # You'll need to associate the alarm signal handler with # play_func like so: $SIG{ALRM} = \&play_func; # Initialize your data here, such as your playlist # Kick-off the play loop by calling play_func once: play_func(); # Put your own looping/interface code here: while(1) { # This will loop until you call 'last;' or exit. # When the alarm signal goes off, Perl will jump to # your alarm-handling code and execute that, then # return to whatever it was doing in here. # This will lead to a slight interrupt in this loop, # but it probably won't be noticeable. }

        Hope that's a useful alternative approach!

Re: Looping in the background of your main program
by ahmad (Hermit) on Dec 31, 2009 at 05:19 UTC

    I am not sure if this would work or not, but this might help you out.

    untested:

    #in your script you may have something like this if ( $ARGV[0] == 1 ) { # your mp3 playing code }else{ # we run the mp3 code & continue doing what we want/need # like this my $pid = system(1,"$0 1"); # you could monitor the pid yourself and/or kill the process when + exiting .. it's up to you. }

    Hopes this will work, try it & post back.