Beefy Boxes and Bandwidth Generously Provided by pair Networks
more useful options
 
PerlMonks  

Starting a process in the background that lives after perl dies.

by ehdonhon (Curate)
on Nov 08, 2001 at 22:49 UTC ( [id://124129]=perlquestion: print w/replies, xml ) Need Help??

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

Hello monks,

I'm having one heck of a time getting this to work. I need to be able to have a perl script (running in a unix environment) start up some process in the background and then exit.

The problem I'm running into is that no matter what I do, either 1) Perl hangs and waits until the background process completes, or 2) The background process dies when perl dies.

So far, the only thing that I've found that actually works the way I want it to, is something like this:

system('run_my_program.sh');
This is followed up by a shell script like this:
#!/bin/sh my_program &

That works great. Whenever it is the shell script that sticks the process in the background it runs just the way I want it to. However, a Perl command like this

system( "my_program &" );
does not. Using the perl fork() command also does not work. As soon as my main perl script dies, all of the children processes get reaped.

I would imagine that if it is possible to have perl make a system call to a one line shell script that does what I want, that it must be possible to bypass the shell script all together and just make perl stick the process in the background on it's own. Any advice would really be appreciated.

Replies are listed 'Best First'.
(jeffa) Re: Starting a process in the background that lives after perl dies.
by jeffa (Bishop) on Nov 08, 2001 at 23:02 UTC
    Proc::Daemon has an Init() method that turns your script into a daemon, and as the docs say: daemon != server.

    Check it out - especially the documention which gives an excellent receipe for writing a robust daemon application.

    jeffa

    L-LL-L--L-LL-L--L-LL-L--
    -R--R-RR-R--R-RR-R--R-RR
    F--F--F--F--F--F--F--F--
    (the triplet paradiddle)
    
Re: Starting a process in the background that lives after perl dies.
by runrig (Abbot) on Nov 08, 2001 at 23:13 UTC
    Perhaps you want to nohup your command in the background??

    And have you looked at "Complete Dissociation of Child from Parent" in perlipc?

    Updated link - fixed bad cut n paste job :-)

      To provide a bit more detail:

      system("nohup xterm&");

      should "run a command immune to hangups, with output to a non-tty"

      Joe.

Re: Starting a process in the background that lives after perl dies.
by DrManhattan (Chaplain) on Nov 08, 2001 at 23:22 UTC
    Use a combination of fork() and exec()
    #!/usr/bin/perl -w use strict; my $pid = fork(); if ($pid == 0) { # This is the child process. # exec() the external program. exec("my_program") or die "could not exec my_program: $!"; } elsif (!defined($pid)) { die "could not fork"; } # Everything below here is the parent process print "This is the parent process\n";

    -Matt

      Thanks,

      Unfortunately that doesn't work. As soon as the main program (the one that did the forking) finishes running, the child process (the one that got forked) gets reaped.

      I even tried modifying that code slightly to incorporate the previous suggestion of using Proc::Daemon::init. It doesn't matter, the child still dies. Is it possible that this is simply something that can only be done in sh and not in Perl?

      Here is my test code (based on your suggestion):
      a.pl :

      #!/usr/local/bin/perl my $pid = fork(); if ($pid == 0) { # This is the child process. # exec() the external program. exec("./b.pl &") or die "could not exec my_program: $!"; } elsif (!defined($pid)) { die "could not fork"; } # Everything below here is the parent process print "This is the parent process\n";
      b.pl:
      #!/usr/local/bin/perl use Proc::Daemon; Proc::Daemon::init; open ( OUT, ">b.out" ); while ( 1 ) { print OUT `/bin/date`; sleep( 2 ); }

      I found that a.pl is calling b.pl, which is outputing the present time to b.out. But then, a.pl exits out, and so does b.pl. This is not the desired result. By the way, I'm doing this on FreeBSD 4.1.1 if that makes any difference.

        Here's the test code I used:
        #!/usr/bin/perl -w # forker.pl use strict; my $pid = fork(); if ($pid == 0) { exec("/tmp/busy_wait.pl"); } elsif (!defined($pid)) { die "could not fork"; } print "This is the parent process\n";
        #!/usr/bin/perl -l # busy_wait.pl while (1) { print "Busy!"; sleep 2; }
        When I execute forker.pl, I get this output:
        [matt@megatron ~]$ /tmp/forker.pl Busy! This is the parent process [matt@megatron ~]$ Busy! Busy! Busy!
        The parent dies, and I get my shell prompt back, but the busy_wait.pl child lives on until I purposefully kill it.

        -Matt

Re: Starting a process in the background that lives after perl dies.
by Asim (Hermit) on Nov 08, 2001 at 22:58 UTC

    Try exec:

    "This function terminates the currently running Perl script by executing another program in place of itself."

    ----Asim, known to some as Woodrow.

      Thanks, but I don't want to exec.. my Perl script has other things that it needs to do. Some times I want to be able to start other processes up at the same time. This is mainly needed in a CGI environment, but not just for CGI.

        perlipc has some stuff you may want to try :

        Complete Dissociation of Child from Parent In some cases (starting server processes, for instance) you'll want to + complete dissociate the child process from the parent. The easiest w +ay is to use: use POSIX qw(setsid); setsid() or die "Can't start a new session: $!"; However, you may not be on POSIX. The following process is reported to + work on most Unixish systems. Non-Unix users should check their Your +_OS::Process module for other solutions. * Open /dev/tty and use the TIOCNOTTY ioctl on it. See tty(4) for +details. * Change directory to / * Reopen STDIN, STDOUT, and STDERR so they're not connected to the + old tty. * Background yourself like this: fork && exit; * Ignore hangup signals in case you're running on a shell that doe +sn't automatically no-hup you: $SIG{HUP} = 'IGNORE'; # or whatever you'd like

        The docs are a little different than an eariler version I found on the Net, so give it a try and see if that solves your problem. If not, look at the perlipc manpage excerpted from the Activestate's Perl UNIX user's e-mail list for a longer program.

        ----Asim, known to some as Woodrow.

        Edit: chipmunk 2001-11-08

        do a fork(), then do an exec(). the exec() will only replace the fork()'ed child.
Re: Starting a process in the background that lives after perl dies.
by mr_mischief (Monsignor) on Nov 09, 2001 at 01:49 UTC
    You should be able to double fork(), then dissociate the new child from the process group, then exec the other program from that grandchild.

    POSIX::setsid() is your friend. POSIX is a core module, too, so its use is not subject to installation issues. Use it like this:
    #!/usr/bin/perl -w use strict; use POSIX qw{setsid}; ### or just 'use POSIX;' if you plan to use other ### functions from it, of course if ( fork ) { { ### grandparent code goes here print "My grandkid should do a cute l'il ls...\n"; } exit; ### die if we're the parent } if ( fork ) { exit; ### die if we're the parent of this one, too. } ### grandchild code starts here POSIX::setsid; ### should be part of a new session now exec '/bin/ls', '.';
    The above program should show a proud grandparent bragging about what its grandkid is doing. The grandchild then sticks around after the grandparent is dead. Use a loop in the grandchild if you need to prove it to yourself. The grandparent can also do whatever you want it to do, too.

    Update:By all means, also close the standard file handles and chdir to the root directory as edebill suggests. I was overlooking this as assumed for serious background tasks, but I should learn sooner or later that my assumptions are not necessarily those of another monk reading my nodes.
      Don't forget to close STDIN, STDOUT and STDERR, and change pwd to "/" so you don't end up with a background process keeping you from unmounting some filesystem later on. I use the following at daemon start time.
      my $pid = fork(); if($pid != 0){ exit 0; } chdir "/"; close STDOUT; close STDERR; close STDIN; POSIX::setsid(); # this takes care of controlling terminals
      Stevens covered this pretty well, I think it was "Advanced Programming in the UNIX Environment" or some such.
Re (tilly) 1: Starting a process in the background that lives after perl dies.
by tilly (Archbishop) on Nov 09, 2001 at 18:07 UTC
    The solution that I use is to use the unix "at" command to launch the process. This is very simple to do, and if your cron is configured properly any messages printed by the job will be sent to you in an email (assisting greatly in debugging). A draw-back, though, is that this is inappropriate for long-running processes. For those I tend to use a cron that tries to restart the process, and then check at startup to see if it is running. (Usually by trying to grab a file lock.)

    For a poor man's parallel process control you can modify this by specifying a random queue to send the job to. OK, pretty poor, but it is surprising how far this one goes.

Re: Starting a process in the background that lives after perl dies.
by Anonymous Monk on Nov 10, 2001 at 16:43 UTC
    Check out exec().

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others drinking their drinks and smoking their pipes about the Monastery: (6)
As of 2024-04-15 13:37 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found