renodino has asked for the wisdom of the Perl Monks concerning the following question:
My initial design used a central ConnectionFactory threaded object to listen()/accept(), then pass the fileno of the created socket over a queue to a free worker thread, which would reconsitute it via IO::Handle::fdopen() and service the client request. While it works in single threaded mode (i.e., no threads), it fails in multithreaded mode during the fdopen() with a "Bad file descriptor" error. Note that the accept()ing thread and the worker threads are "segregated", i.e., the workers do not descend directly from the listener, but are siblings of it.
I've worked around the issue thus far by changing the design:
While it work for small numbers of connections, I'm concerned it may not handle large numbers (>100) of connections. I've considered letting all the worker threads select() on a nonblocking listen socket, and allowing "nature to take its course", but I'd much prefer a centralized mgmt of load balancing across threads if possible, rather than relying on chaos.
Is this inability to reconstitute file handles across segregated threads expected behavior ? I could undertstand if this were a process based model, but shouldn't threads be more flexible ? Or is this just another Win32ism ?
Update: My bad. I've found/fixed the problem. Corrected code included. Guess I'm too dense to know how to use the modules I write...
Here's the corrected code that solves the problem:
use IO::Socket; use threads; use threads::shared; use Thread::Queue::Duplex; use strict; use warnings; # # create a TQD # create 2 threads # wait for them # my $tqd = Thread::Queue::Duplex->new(ListenerRequired => 1); my $thrdA = threads->new(\&threadA, $tqd); my $thrdB = threads->new(\&threadB, $tqd); $thrdA->join(); $thrdB->join(); print "Done.\n"; sub threadA { my $tqd = shift; $tqd->wait_for_listener(); # # open listen socket # pass fileno to other thread # my $listenfd = IO::Socket::INET->new( LocalPort => 9088, Proto => 'tcp', Listen => 10); die "Can't open listener: $!" unless $listenfd; # # now accept a connection # my $fd = $listenfd->accept(); # # !!!WRONG!!! # its enqueue_and_wait to block!!! # # my $resp = $tqd->enqueue('newfd', $fd->fileno()); my $resp = $tqd->enqueue_and_wait('newfd', $fd->fileno()); $listenfd->close(); return 1; } sub threadB { my $tqd = shift; $tqd->listen(); my $req = $tqd->dequeue(); my $id = shift @$req; my $fn = $req->[1]; print "fileno is $fn\n"; my $fd = IO::Socket::INET->new(); die "Can't acquire the socket: $!" unless $fd->fdopen($fn, '+>'); my $tpage = '<html><body> <i><h1>Got your click!!!</h1></i> </body></html>'; my $pglen = length($tpage); my $opage = "HTTP/1.0 200 OK Content-type: text/html Content-length: $pglen $tpage"; $fd->send($opage, 0); $fd->close(); $tqd->respond('newfd', 1); return 1; }
|
|---|
| Replies are listed 'Best First'. | |
|---|---|
|
Re: Passing sockets between segregated threads
by BrowserUk (Patriarch) on Oct 20, 2005 at 16:43 UTC | |
by renodino (Curate) on Oct 20, 2005 at 17:11 UTC | |
by BrowserUk (Patriarch) on Oct 20, 2005 at 17:55 UTC | |
by renodino (Curate) on Oct 20, 2005 at 18:01 UTC | |
by BrowserUk (Patriarch) on Oct 20, 2005 at 18:03 UTC |