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

See code below. Is it by design that calling exit() (I know, it is not recommended) does not call the exit handler?

Background: because signals do not work on Windows, I created a thread that waits for a Windows event (Win32::Event). Our tests are scheduled in a parallel scheduler, but if a test exceeds its maximum running time, the scheduler signals (Unix, kill, Windows: event) the running test to terminate. Because the test need to cleanup test data, I have to do pre-exit cleanup. That information is stored in hash tables. These hash tables can be shared, but sharing multi-dimensional hash tables is somewhat cumbersome (and prone to programming errors).

Therefore, if the exit() call in the thread triggered the END exit handler, I could perform the cleanup work there, without having the need to share my data structure across a thread. But remember: using a thread + event is already a workaround. If signals will work, or if you know another method to stop a (hanging) test (can hang on waitpid() on a child, can hang on a long-term operation, whatever) but including at-exit cleanup work.

So the intention is that a signaled thread should abort any operation in the main thread and perform the cleanup code in the exit handler. Any suggestions are welcome.

use strict; use threads; use threads::shared; my $inthread : shared; END { print "Exit handler called (inthread=$inthread)\n"; } # the exit handler (END block) is never called when a thread performs +an exit() # using a lower main sleep time will result in a normal exit of the ma +in thread. my $threadsleeptime : shared = 5; my $mainsleeptime = 2; my $thread = async { $inthread = 1; sleep($threadsleeptime); print "Sleep in thread finished\n"; # force also main thread to exit # but bypasses exit handler in END block exit(1); } sleep($mainsleeptime); print "Sleep in main finished\n"; $thread->join if ($thread); print "End of main program\n";

Replies are listed 'Best First'.
Re: Calling exit() in thread does not call exit handler
by BrowserUk (Patriarch) on Oct 29, 2014 at 16:05 UTC
    calling exit() (I know, it is not recommended)

    Then don't do that.

    If you want to trap an abnormal exit from a thread, use eval & die just like you normally would:

    use strict; use threads; use threads::shared; my $inthread : shared; # the exit handler (END block) is never called when a thread performs +an exit() # using a lower main sleep time will result in a normal exit of the ma +in thread. my $threadsleeptime : shared = 2; my $mainsleeptime = 5; my $thread = async { eval { $inthread = 1; sleep($threadsleeptime); print "Sleep in thread finished\n"; die('abnormal exit'); }; if( $@ =~ /^abnormal exit/ ) { ## do cleanup print "doing cleanup in thread\n"; } } sleep($mainsleeptime); print "Sleep in main finished\n"; $thread->join if ($thread); print "End of main program\n"; __END__ C:\test>junk29 Sleep in main finished Sleep in thread finished doing cleanup in thread End of main program

    With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
    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.
      I don't like to catch an abnormal exit of my thread, but I use a thread to be able to force an exit of the main thread, including cleanup (that belongs to the main thread).

      I know gathered all required information in a shared multi-dimensional hash table, which worked well. It just took some time to solve all invalid scalar errors that happened on runtime (because not all required data was correctly marked as shared).

        I use a thread to be able to force an exit of the main thread

        That is really, really, really bad design -- (*)like designing a train where the only way to get off is to smash a window and jump; and hoping that there'll be somewhere soft to land -- and it will come back to bite you!

        * That's a pretty terrible analogy; maybe this is better: Like designing a satnav such that when you reach your destination, it kills your engine dead and then relies upon the anti-skid brakes and collision avoidance systems to bring you to a halt safely.

        I seriously caution you against taking this design forward. Especially when it is so simple to avoid it:

        use strict; use threads; use threads::shared; my $inthread : shared; sub doCleanUp { print "doing cleanup"; } my $threadsleeptime : shared = 2; my $mainsleeptime = 5; my $thread = async { eval { $inthread = 1; sleep($threadsleeptime); print "Sleep in thread finished\n"; die('abnormal exit'); }; if( $@ =~ /^abnormal exit/ ) { print "triggering cleanup in main\n"; return -1; } return 0; }; $thread->join() and doCleanUp() if ($thread); print "End of main program\n"; __END__ C:\test>junk29 Sleep in thread finished triggering cleanup in main doing cleanupEnd of main program

        With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
        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.