in reply to Re^5: CLONE/DESTROY want work at all??
in thread CLONE/DESTROY want work at all??

That's the question :)

Replies are listed 'Best First'.
Re^7: CLONE/DESTROY want work at all??
by BrowserUk (Patriarch) on May 23, 2009 at 04:07 UTC

    Hm. Then it's a very difficult one to answer--because it not clear from either your description or code exactly what it is you are trying to achieve?

    For example, you say:

    i need a clean destructor for system resources like file handles,

    Why do you need to handle the destruction of these?

    And why is your %MY_CXT shared? And global?

    And as tilly already pointed out, why are you incrementing the reference counts of everything every time CLONE is called?

    The main problem here is that your are posting do-nothing code that serves only to demonstrate that you are doing something wrong--not what it is that you are actually trying to achieve. That makes it impossible to correct because we cannot infer from what you are doing (wrong), what you should be doing, to make it right. Whatever it is?

    Have you read this: http://perldoc.perl.org/perlmod.html#Making-your-module-threadsafe?

    Because having played with the code you posted and simplified and simplified, it seems clear from this statement:

    CLONE is called correctly, but DESTROY is called to less.

    That you are expecting CLONE to be called for each thing (object) cloned, each time it is cloned. And that simply isn't the case. Note (in the docref above) where it says: "CLONE will be called once as a class method for every package that has it defined (or inherits it). It will be called in the context of the new thread".

    Ie. For any given package, CLONE will be called on each new thread, once, for each class that is loaded at the time the thread is spawned. Not for each instance!

    Conversely, DESTROY(), will be called once on each thread, for each instance that exists.

    To demonstrate, this simplified version of your code creates two instances of the class and passes them to a thread, which passes them on to a second thread. Both threads then die before the process is repeated:

    It produces this output:

    C:\test>junk10 MAIN[0]: Creating thread 1 passing objs: Class=HASH(0x2683c0) & Class= +HASH(0x2c4e50) >CLONE[1]: <CLONE[1]: this; Class THREAD[1] L:0 running >CLONE[2]: <CLONE[2]: this; Class THREAD[2] L:1 running THREAD[1] L:0 finished >DESTROY[1]: <DESTROY[1]: this: Class=HASH(0x3c6dc78) >DESTROY[1]: <DESTROY[1]: this: Class=HASH(0x3c6dcc0) THREAD[2] L:1 finished >DESTROY[2]: <DESTROY[2]: this: Class=HASH(0x3d34148) >DESTROY[2]: <DESTROY[2]: this: Class=HASH(0x3d34178) >DESTROY[0]: <DESTROY[0]: this: Class=HASH(0x2c4e50) >DESTROY[0]: <DESTROY[0]: this: Class=HASH(0x2683c0) MAIN[0]: Creating thread 2 passing objs: Class=HASH(0x2683c0) & Class= +HASH(0x268120) ...

    Note that although two instance of Class are created by main and passed in turn to each of the two threads, Class::CLONE() is only >entered and <exited once in the context of each of those two threads.

    However, Class::DESTROY() is called is called six times! Twice (once for each instance) in the context of each of the spawned threads to destroy the clones created for those threads; and when those have both been destroyed, twice in the context of the main thread (0) to destroy the originals.


    I'm hoping that will start to make what you are doing wrong in trying to achieve whatever you are trying to achieve clear to you? If that is the case, I'd appreciate feedback both on whether it helped? And what you are trying to achieve? Because whilst the doomsayers have been fumbling their gums with doom and gloom on a subject they obviously know nothing about, I've spent a not inconsiderable portion of the last two days trying to work out what you are really trying to do.

    I appreciate that you are trying to track resources, but if the resources are perl allocated--ie. any standard perl allocated resource like file handles; even if allocated from within XS code--then you need to do quite literally nothing, and Perl will take care of their management, including destruction.

    But if you are genuinely allocating non-Perl resources on the basis of calls to CLONE(), what are those unmanaged resources? Are you allocating them on a per-thread basis? Or a per-instance basis? Or a per-instance-per-thread basis? Or ... ?

    I kept hoping that you would either volunteer some more (useful) information, or that someone would ask you for it before jumping to knee-jerk conclusions; or trotting out the "threads are bad; or hard; or not unix-y; or I-got-bitten-by-them-on-my-first-attempt-when-I-didn't-know-what-I-was-doing-so-now-I-tell-everyone-that-mentions-them-they-are-scarey-and they-shouldn't-use-them" dogmas.


    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.
      Thank you for your reply.
      Why do you need to handle the destruction of these?
      Because i wanted to make Perl faster, smaller and even better. For example i wrote the Socket::Class module. It handles IPv6, includes SSL and it uses the C socket API instead of the PerlIO layer. Since MY_CXT clones with every thread, i'm using a global structure and a thread mutex to hold the data for Socket::Class. It works fine, is fast and saves memory. But in this case i need the correct time to destruct the shared data structure. I also started writing some new database drivers, which require similar mechanism.

      The shared and global %MY_CXT hash was not a good example. But i used it to prevent from answering "take a look to MY_CXT mechanism". Because i did already many times :)

      I believe i also did already understand what CLONE does. It's called once a new thread is created for each class or inherited class. Please see the following from perlmod/perldoc:

      If you want to CLONE all objects you will need to keep track of them per package.

      Because of this i'm incrementing the reference counts every time CLONE is called.

      Your example works as expected as long as the sub threads close before the main thread creates new ones.
      Try it out. Set the sleep time in the sub threads to a higher value then the main thread sleep time. The reference counts become different. I think it starts at the point where the main variables are overwritten. ($obj1 = Class->new())
      This is the problem that i have :)

      Henceforth, I dub thee TABOHONU - threads are bad; or hard; or not unix-y;

      OR IGBBTOMFAWIDKWIWDSNITETMTTASATSUT - I-got-bitten-by-them-on-my-first-attempt-when-I-didn't-know-what-I-was-doing-so-now-I-tell-everyone-that-mentions-them-they-are-scarey-and they-shoudln't-use-them