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

This is ActiveState Perl v5.10.0 on Windows:
use warnings; use strict; use POSIX; my $skip_end = 0; END { print "this should print once\n" } if (fork) { print "parent\n"; sleep 1; } else { print "child\n"; $skip_end ? _exit(0) : exit(0); } print "last line of program\n";

Output when $skip_end == 0:
child this should print once parent last line of program this should print once

OK. Now I want to skip the END block for the "child". Output when $skip_end == 1:
parent child

The output I am expecting:
child parent last line of program this should print once

I know that POSIX::_exit() stops perl from doing END blocks (among other things that I'm fine with). But it's getting in the way of other threads.

Another side question: How can I detect if code is running in a fork-emulation thread?

Replies are listed 'Best First'.
Re: How to skip END blocks with threads?
by BrowserUk (Patriarch) on May 04, 2009 at 08:34 UTC

    Like this?

    use warnings; use strict; use threads 'exit' => 'threads_only'; my $ppid = $$; END { return unless $$ == $ppid; print "this should print once\n" } if (fork) { print "parent\n"; sleep 1; } else { print "child\n"; threads->exit; } print "last line of program\n"; __END__ c:\test>junk2 parent child last line of program this should print once

    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.
      and you're mixing threads with forks now ? is this good or bad , I can't tell
        and you're mixing threads with forks now?

        Under windows, they are the same thing!

        fork is emulated using threads.

        Besides which, the only reason I need to use threads, is to import the threads->exit call, which simply terminates the current thread (fork-emulation) without terminating the process as exit or POSIX::_exit() would.

        is this good or bad, I can't tell

        I'm no great lover of the fork emulation--is has too many caveats to be particular useful--once once you've chosen to go that route, you're already using threads implicitly, so importing the extra routine to achieve the goal just makes sense.


        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        "Science is about questioning the status quo. Questioning authority".
        In the absence of evidence, opinion is indistinguishable from prejudice.
      Thanks, that works great. Unfortunately, I cannot affect the way the END block(s) are written.

      I'm trying to have my module IPC::Exe avoid doing END blocks once exec fails in a child, so it doesn't act in a surprising way. From the looks of it, I may just abandon the idea (in favor of consistency) because I can't tell when threads are used.

      exit and die seem to do the right thing when called inside a thread or a different process, but they also do END.
        Unfortunately, I cannot affect the way the END block(s) are written.

        Then add an END block in your code, prior to useing the modules (any modules), whos end blocks you wish to disable, and call thread->exit() within that END block. Eg.

        #! perl ... # main.script my $originalPid = $$; END{ return if $$ == $originalPid; require threads; threads->exit; } use Foo; use Bar; ...
        • By putting your END block ahead of any modules you use, you ensure that your END block is called first.
        • If the curent pid == the pid when the code first ran, you are the parent, so quit early and allow the parent to run any END end blocks set up by the modules it uses.
        • Otherwise, you are a child, so call threads->exit before any other END blocks are called.

        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        "Science is about questioning the status quo. Questioning authority".
        In the absence of evidence, opinion is indistinguishable from prejudice.
        When modules are loaded (like threads), they leave an entry %INC (besides creating an entry in %::)
Re: How to skip END blocks with threads?
by spx2 (Deacon) on May 04, 2009 at 04:02 UTC
    I hope you know that $skip_end is not the same in the child as it is in the parent. If you want you can
    use threads::shared; my $skip_end :shared;
    replace the fork with creating a thread and then you can use $skip_end across threads.
Re: How to skip END blocks with threads?
by Anonymous Monk on May 04, 2009 at 00:54 UTC
    I know this may sound stupid, but don't add END blocks. What is a fork-emulation thread?
      On Windows, fork is emulated with threads. The code is actually running in separate threads after (fork) is called.

        Please see this and Perlmonks - "What is the difference between Windows fork an Unix fork ?"

        A relevant bit of MSDN says :

        "One of the largest areas of difference is in the process model. UNIX has fork; Win32 does not. Depending on the use of fork and the code base, Win32 has two APIs that can be used: CreateProcess and CreateThread. A UNIX application that forks multiple copies of itself can be reworked in Win32 to have either multiple processes or a single process with multiple threads. If multiple processes are used, there are multiple methods of IPC that can be used to communicate between the processes (and perhaps to update the code and data of the new process to be like the parent, if the functionality that fork provides is needed). For more on IPC, see Interprocess Commuications."