in reply to Sharing sockets between the main script and thread

Try it this way:

#! perl -slw use strict; use IO::Socket; use threads qw[ yield ]; use threads::shared; use Thread::Queue; sub worker { my $Q = shift; while( my $fnum = $Q->dequeue ) { open my $client, "+<&$fnum" or die $!; while( <$client> ) { print $client $_; print $_; } close $client; } } our $WORKERS ||= 5; my $Q = new Thread::Queue; my @workers = map threads->create( \&worker, $Q ), 1 .. $WORKERS; my $server = IO::Socket::INET->new( LocalHost=>'localhost:54321', Listen=>5, Reuse=> 1 ) or die $^E; while( my $client = $server->accept ) { my $fno = fileno( $client ); $Q->enqueue( $fno ); yield while $Q->pending; ## wait until a worker dups the socket close $client; ## Now we can safely close it. }

Rational: The socket won't be released until all open handles to are closed. You are currently getting one handle from the accept; creating a second within the thread (via the fileno). When the client goes away, the threads read loop ends and it's handle gets (explicitly or implicitly) closed. But, the handle in the main thread remains and the socket will not be finalised until it is closed, but there is nothing in the main thread that will do that. If you close the socket prior (or even immediately after!) queuing the fileno for the worker thread, by the time the worker gets it, there is no socket to dup.

So, when accept returns, take the fileno, queue it, then yield your timeslices until the queue is empty. Now, a worker has dequeued the fileno and opened it's own handle to the socket, so it is safe to close the main threads copy. Everyone is happy :)


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.
"Too many [] have been sedated by an oppressive environment of political correctness and risk aversion."

Replies are listed 'Best First'.
Re^2: Sharing sockets between the main script and thread
by markseger (Beadle) on Nov 25, 2008 at 13:01 UTC
    Excellent! I couldn't quite do it the way you suggested for a couple of reasons, one being that I'm doing my accepts in the thread vs the main stream code so the logic would need to be reversed but more significant is the fact that the thread is stuck in a select->can_read(), waiting for connection requests and can't do that and watch a queue at the same time unless I wrap all that in an outer loop with a timeout and didn't want to do that.

    Nevertheless, since I am passing around the file numbers in a shared hash from the thread to the main code, I'm able to set it to a 'special' value when the socket is closed in the thread to tell the main line to close his end as well.

    In any event, the key to all this is it need to close the second descriptor and that did the trick. Seems to work like a champ, at least so far...

    -mark