Beefy Boxes and Bandwidth Generously Provided by pair Networks
Syntactic Confectionery Delight
 
PerlMonks  

fork & END

by tlm (Prior)
on Sep 07, 2005 at 00:30 UTC ( [id://489730]=perlquestion: print w/replies, xml ) Need Help??

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

In one of my modules I have a sub that performs a fork. It works fine for the most part, but when I also use the standard module File::Temp I get some weird behavior. This is because File::Temp has END blocks that get triggered prematurely when the child exits. Therefore, my module most likely won't play well with any other module that uses END blocks.

I have not been able to come up with a satisfactory solution to this problem. The best I can think of is something like:

package Forker; #... sub forker { die "fork failed: $!" unless defined( my $pid = fork ); return if $pid; # break a leg kill 9, $$; }
but this seems rather brutal.

Afterthought: More generally, it is clear that fork and END don't mix too well, so I wonder what "best practices" could inform this issue. I.e., should one refrain from using END blocks (or alternatively fork) in a module? Or should every module that uses an END block also have a BEGIN block in which the initial value of $$ gets stored, so that END blocks can determine whether they were called from the parent or not?

I'd very much like to read your opinions on this. Thanks in advance!

the lowliest monk

Replies are listed 'Best First'.
Re: fork & END
by itub (Priest) on Sep 07, 2005 at 00:58 UTC
    You can try something like this:
    use POSIX qw(_exit); if (fork) { # parent } else { # child. # do stuff _exit(0); # "simple exit", does not run END } END { # do stuff; only run on parent }
Re: fork & END
by xdg (Monsignor) on Sep 07, 2005 at 00:57 UTC

    Are you on Win32? File::Temp claims that it doesn't unlink things in child processes, but if you're on Win32, you're only getting a pseudo-fork (see perlfork).

    In any case, one approach is just to tell File::Temp not to unlink things automatically (with UNLINK => 0) and do your own cleanup. It's hard to be more specific with suggestions without knowing how you're using File::Temp.

    -xdg

    Code written by xdg and posted on PerlMonks is public domain. It is provided as is with no warranties, express or implied, of any kind. Posted code may not have been tested. Use of posted code is at your own risk.

      Thanks.

      Are you on Win32? File::Temp claims that it doesn't unlink things in child processes...

      I'm having a hard time locating this in the docs. Grepping "child" got me nothing. What should I search for? (FWIW, I'm using version 5.8.6 of Perl, and version 0.14 of File::Temp.)

      My OS is Linux.

      The problem I'm having results from the CLEANUP option of File::Temp::tempdir, which I'm setting to 1.

      I guess I was wondering if there was a standard workaround for this kind of situation.

      the lowliest monk

        I think you may want to upgrade. See the ChangeLog for File::Temp. 0.15 improved forking support. If you look at the CPAN docs, there's a brief comment in a section at the very end called "forking".

        In writing File::pushd, I didn't set CLEANUP and used File::Path to remove the directory precisely when I wanted to (in my case, earlier than END). You could do that in your parent process after you reap all the children. But I'd try your script with a newer version of File::Temp and see if that resolves things for you.

        -xdg

        Code written by xdg and posted on PerlMonks is public domain. It is provided as is with no warranties, express or implied, of any kind. Posted code may not have been tested. Use of posted code is at your own risk.

Re: fork & END
by polettix (Vicar) on Sep 07, 2005 at 09:56 UTC
    itub's solution is probably what you're looking for not to be brutal, but I'd object that you're probably looking the problem from the wrong point of view.

    Doing a little shift to a similar field for the moment, it's clear that not all libraries are good to be used in a multithreaded world. This is because many times the library assumes to be the only owner of some resources, and the multithreaded environment does not guarantee this any more. The bottom line is that you have to adapt the library to work in the new environment, avoiding dirty tricks in the environment itself.

    This case seems pretty similar. What if the module you're using is already fork-robust, but still needs to execute its END block to work properly in the quitting father? Skipping the END block would simply break it, and this doesn't seem too fair. Again, I think that the bottom line is that you have to make sure that the module is fork-robust, and not try to put dangerous work-arounds outside of them. The upgrading suggestion from xdg points in this direction IMHO (... 0.15 improved forking support...).

    Just my 2c as usual,

    Flavio
    perl -ple'$_=reverse' <<<ti.xittelop@oivalf

    Don't fool yourself.
Re: fork & END
by xdg (Monsignor) on Sep 07, 2005 at 11:53 UTC

    Regarding your afterthought: I don't really like END blocks, particularly for modules, because they create another form of the "action at a distance" problem. I would prefer that any module that relies on them say so explictly and with appropriate warnings. I know they are useful in some cases -- but they can easily create problems for downstream users, as you've discovered.

    The other thing you asked about is fork. Anytime one is trying to do concurrency, whether forks or threads, a whole host of new concerns inevitably arise. I think it's very important to think through exactly what side effects might arise through concurrency, particularly around cleanup/teardown code. END blocks are just one example. What about object destructors? Assuming that one is finished with some resource is one thread/process may or may not be OK depending on the nature of the cleanup. It may be useful to store $$ in BEGIN as a way of limiting destruction action to the parent process/thread, but it may also be useless in many cases.

    Ultimately, I think END should be an infrequent tool, but I think that the onus is on those forking/threading to anticipate side effects and code to prevent them. What makes END so insidious is that one can't defuse it, whereas one could always wrap a misbehaving DESTROY method to call the original only if it has been called from within the parent process.

    -xdg

    Code written by xdg and posted on PerlMonks is public domain. It is provided as is with no warranties, express or implied, of any kind. Posted code may not have been tested. Use of posted code is at your own risk.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://489730]
Approved by friedo
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: (3)
As of 2024-04-25 21:48 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found