develooper Front page | perl.ithreads | Postings from February 2008

Re: Passing an IO:Handle to a Thread

Thread Previous | Thread Next
From:
Chris Hall
Date:
February 28, 2008 05:33
Subject:
Re: Passing an IO:Handle to a Thread
Message ID:
DgRkSPY3erxHFwcI@agrotera.halldom.com
On Wed, 27 Feb 2008 Dean Arnold wrote
>See embedded:

Thank you.

>Chris Hall wrote:
...
 >>  I can see that Thread:Queue creates a shared array and then blesses
 >>  it.  For several threads to use the queue one needs to pass the
 >>  object.  If the queue object (reference) is stored in a shared
 >>  scalar, will that work ?  Does each thread need to bless the thing ?

>Note that its *not* required to pass the the queue - if you create the
>queue *before* the threads, the threads automagically get a CLONEd
>version of the queue (like process fork(), which ithreads attempts
>to emulate).

I've been thinking about a something similar to Thread::Pool in which a 
number of threads are started early and wait on a queue for things to 
do.  A thing-to-do-bundle (object !) might include (a) a subroutine 
reference, (b) some arguments, (c) a queue to post the result(s) to.  It 
is clear that there are a number of hoops to be negotiated to make this 
happen !

 >>  Does an object shared in this way get DESTROYed once or once per
 >>  thread ?

>As to shared object destruction:
>
>pre-5.10.0: once per thread, requires some extra bookkeeping to make sure
>it "does the right thing"

OK.  I've seen stuff keeping track via CLONE.

>5.10.0: once in the last referencing thread (fixed in CORE)

Ah.  FWIW this doesn't appear in the perldelta.  I may be overestimating 
the importance of DESTROY, though.  [I note that IO::Handle contains an 
empty DESTROY to emphasise that some other mechanism is taking care of 
things.]

 >> 2. GLOBS in general and IO::Handle objects in particular.
....
 >>     I suppose I can pass $FH->fileno and use fdopen in the worker
 >>     thread.
 >>     If so, I've got two IO::Handle objects in separate threads, both
 >>     capable of doing stuff...
 >>     What happens when I close one of the IO::Handles ?  Or one is
 >>     DESTROYed ?

 >Yes, you have to pass the fileno and recreate the handle object in the
 >receiving thread. As this is essentially a dup() operation, each 
 >filehandle is independent of the others (other than they access the
 >same I/O target).

Most problems can be solved by introducing an extra level of indirection 
:-)

 >          Which is fine for block I/O, but for streams (e.g., sockets),
 >its best to make sure only 1 thread is using the handle.

OK.  Sadly, such things depend on the implementation and that depends on 
the underlying libraries etc., which is hard to document, clearly. 
Unfortunately, with threads the usual expedient of sucking-and-seeing is 
unreliable -- given that things are no longer deterministic.

 >PS: if passing a socket from a listener to a child worker thread, be
 >sure the child got the socket reopened before closing in the listener!

An SMOP :-)

>>  3. Cannot assign sub addresses to a shared variable.
>>     If find that I cannot do: my $r_sub :shared = \&sub...
>>     which requires some other work around ?

>My first question is "Why would you want to do that ?"

Well...  I was thinking about passing a ref:Sub -- as above.  It looks 
as though the closest approach will be to initialise an array of ref:Sub 
before starting the first thread, and passing an index.  [Or I could 
just pass the name and (a) eval it or (b) poke around the Stash (call by 
name, yet).]

>FWIW: Thread::Apartment supports proxied closures to pass closures
>between threads, but the closure resides and executes
>inside its originating thread.

[An Apartment looks like a Monitor to me, with a form of RPC rather than 
direct calls.]

>>  4. More specifically -- IO::Socket objects.
>>     Assuming a listening socket in one thread, but each incoming
>>    connection should be handled in a separate thread...  The accept
>>    action:
>>        $connection_socket = $listen_socket->accept()
>>     requires that the connection thread can be passed either the
>>    $connection_socket or the $listen_socket.
>>     Assuming the fdopen trick works, what about all the properties 
>>held
>>    in the hash is the IO:Socket object ?
>
>I've used this effectively wo/ issues in a number of apps.
>I believe HTTP::Daemon::Threaded has code for that, you might
>want to review it. (but I could be misremembering; sadly, its been awhile
>since I touched it)

Thanks for the pointer.  I will go study.

Chris
-- 
Chris Hall               highwayman.com            +44 7970 277 383

Thread Previous | Thread Next


nntp.perl.org: Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at ask@perl.org | Group listing | About