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

Is there any way to influence the order destructors are called when Perl shuts down (because of a signal or exit)? And if not, any ideas for how to handle this situation better?

Here's what I've got going on. I'm operating a device via the serial port. My object (RFID::Matrics::Reader) is sending a command to the device telling it "Hey, collect data as fast as you can and send it to me!" When the object is destroyed (usually by program exit on SIGINT), I'd like to send a command down the serial line that says "OK, thanks, you can stop now." But the COM port object is being destroyed before the Reader object, so I can't access the serial device object to send commands.

Thanks for any ideas!

Replies are listed 'Best First'.
Re: Destructor Order
by tilly (Archbishop) on Apr 03, 2004 at 03:26 UTC
    There is no easy way to guarantee that the COM port object is still there when you destroy the Reader object if the destruction happens during global destruction (which it sounds like it may be in your case). The reason is that global destruction goes by force, and nobody is safe (necessary to be sure that circular references get cleaned up). I believe that 5.8 has a hack to make sure that things often get cleaned up in a convenient order, but there are cases where that fails.

    Instead arrange to have the object cleaned up in an END block. END blocks are processed before global destruction, and so you can safely rely on things that you expect to still find alive, not being destroyed out of order.

      Yes, the problem is happening during global destruction.

      I tried an END block, and it works, with some caveats. It seems END blocks don't fire if the script exits from an uncaught signal, which is how the script is exiting, at least while I'm testing. Adding signal handlers that just call exit(1) seems to work fine, though, although it feels kludgey.

      Thanks!

        Just switching to use lexicals instead of package variables should avoid global destruction and let your objects be destroyed as their refcounts dictate, e.g.:
        $ perl -w sub DESTROY { warn $_[0]->{name} } my $inner = bless {name => "inner"}; my $outer = bless {name => "outer", inner => $inner}; __END__ outer at - line 1. inner at - line 1.
Re: Destructor Order
by Zaxo (Archbishop) on Apr 03, 2004 at 02:08 UTC

    The first replies you have are excellent technical ways to enforce a destruct order. They will work fine for you. You may want to use OO principles to get a more direct and self-contained solution.

    Since the "Thanks, stop now" command is for the serial port connection, you can make it part of that object's destructor by including it in a sub DESTROY for the COM port object.

    After Compline,
    Zaxo

      Will they really influencing the order destructors are called during global destruction? There doesn't seem to be general agreement that they will. They seem to involve holding refernces, but my Reader object is holding a reference to the COM port object, but is nonetheless destroyed before it. Maybe I'm missing something...

      Regardless, subclassing the COM port object is a clever idea. Thanks!

Re: Destructor Order
by BrowserUk (Patriarch) on Apr 03, 2004 at 06:07 UTC

    If the main cause of uncontrolled termination is interuption via sigint, then installing a signal handler $SIG{INT} = sub{ #Stop now }};and perfroming your clean up there may be in order.

    END{} blocks aren't run when programs are interupted by sigint(2) (under win32 at least).


    Examine what is said, not who speaks.
    "Efficiency is intelligent laziness." -David Dunham
    "Think for yourself!" - Abigail
Re: Destructor Order
by TomDLux (Vicar) on Apr 03, 2004 at 00:54 UTC

    Develop a subclass which takes and saves a reference to the COM port ... should take five or ten lines of code. That way, you're guaranteed that the port exists until the reader is gone.

    --
    TTTATCGGTCGTTATATAGATGTTTGCA

      No, you're not guaranteed of that.

      You are guaranteed unless the object is destroyed in global destruction, which seems to be the case here.

Re: Destructor Order
by cormac (Acolyte) on Apr 03, 2004 at 01:21 UTC
    You could create an object class that inherits from your RFID::Matrics::Reader class, additionally implementing a tied element using perltie and BSD::Resource to deal with these events accordingly.

    --
    Real men use curlies.