Beefy Boxes and Bandwidth Generously Provided by pair Networks
XP is just a number
 
PerlMonks  

Thread::Apartment, how do I use main:: subs?

by wilsond (Scribe)
on May 10, 2009 at 22:32 UTC ( [id://763161]=perlquestion: print w/replies, xml ) Need Help??

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

I'm using Thread::Apartment to create threads. It's pretty nice since it deals with closures and all that for me.

I need to be able to have a thread make use of subs that are in main:: and in the main thread's context.

For example, one of the things I want to be able to do:

One of my threads runs an XMPP connection. I want to be able to create a new thread (run by Thread::Apartment) on demand from a request coming in on the XMPP connection. I don't want the thread to be a child of the XMPP thread, but of the main thread itself.

I tried passing a CODEREF from main into the thread upon creation, but it kills the XMPP thread when it tries to use that CODEREF. (Thread 1 terminated abnormally: Can't call method "ta_invoke_closure" on an undefined value at Thread/Apartment/Closure.pm line 62, <FH> line 72.) I tried wrapping the CODEREF with T::A::register_closure(), but that didn't help either. I think it's more a problem of my understanding T::A than it is of anything else. I can't figure it out.

The best I came up with (before using T::A) was to have a threads::shared array (to be used as a queue) in main that the threads could write to. The loop in main would check the array/queue and perform actions on it. This feels hackish and doesn't do all of what I'm hoping I could accomplish.

Right now, I have a T::A thread that I use as a controller that keeps track of all of the other T::A threads and passes the T::A::Client ref for other threads to use when they need to communicate with the other threads directly. It doesn't take care of interacting with the main thread, though.

Does anyone have experience using Thread::Apartment and has an idea how to do this? Thanks!

Question Edit: Is there a way to "convert" the main thread into an apartment so I can pass its T::A::Client handle to the other apartments? That seems like it'd do the trick for my purposes. I don't want to have it spawn a new thread for this to happen, just alter the main thread in such a way that it is accessible via T::A::Client.


I'm a Linux user. You wouldn't know it since I mostly ask Windows questions. Whee.
If you want to do evil, science provides the most powerful weapons to do evil; but equally, if you want to do good, science puts into your hands the most powerful tools to do so.
- Richard Dawkins

Replies are listed 'Best First'.
Re: Thread::Apartment, how do I use main:: subs?
by renodino (Curate) on May 11, 2009 at 20:56 UTC
    Sorry, my memory is a bit fuzzy on T::A, but iirc the current version didn't play well outside of an explicitly created object, so main:: might not be runnable in an apartment. I vaguely recall trying to hack something together to do that for an apartment threaded Tk.

    My own use of T::A has always been to use main:: as a just a launcher, and any actual processing was wrapped in objects which could be mapped to apartments.

    Sorry I can't shed more light; I used T::A for a major project a couple years ago, but haven't had a reason to touch it in awhile.


    Perl Contrarian & SQL fanboy

      What I've done (maybe temporary) is to use main to spawn a package called LeafBridge::Client within the main thread and use that to spawn the LeafBridge::Client::Controller apartment. On spawn of this controller, I pass in the handle to $self (LB::Client). LB::C::Controller spawns all of the other apartments by calling $client->spawnApartment($controllerClient). $client being the LB::Client handle that was passed in and $controllerClient being the T::A::Client handle. That spawnApartment is called in the context of the LB::C::Controller apartment thread, not in the main thread. Since LB::Client doesn't do anything except run a loop that calls $controller->tick every second, it doesn't really do anything else but provide access to the apartment creation functions and to create the first apartment (LB::C::Controller). LB::C::Controller tracks all apartment threads and allows any apartment to talk to any other apartment by calling $controller->thread('LeafBridge::Client::XMPP')->send(@args) (the thread method passes the T::A::Client handle of the LB::C::XMPP apartment to the caller; send() is a method within the LB::C::XMPP apartment itself (it could be any arbitrary method in the requested apartment thread)). It seems to work well for now. It feels hackish, but it's the best I could do with the knowledge I have right now.


      I'm a Linux user. You wouldn't know it since I mostly ask Windows questions. Whee.
      If you want to do evil, science provides the most powerful weapons to do evil; but equally, if you want to do good, science puts into your hands the most powerful tools to do so.
      - Richard Dawkins

        By the way, the "workaround" I've presented above is terribly inefficient. My app is running at 400MB right now and it hardly does more than load. Memory leak anyone? It's beyond time for me to be digging myself out of that leak. *whee*


        I'm a Linux user. You wouldn't know it since I mostly ask Windows questions. Whee.
        If you want to do evil, science provides the most powerful weapons to do evil; but equally, if you want to do good, science puts into your hands the most powerful tools to do so.
        - Richard Dawkins

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://763161]
Approved by planetscape
Front-paged by tye
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others surveying the Monastery: (3)
As of 2024-04-19 05:45 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found