I've been working on a simple http server that keeps a pool of threads
around that do multiple crops on an image.

It's a very simple blocking webserver that handles 1 request per
connection. It uses a Thread::Queue::Multiplex (TQM) to assign the
request to the corresponding image cropping thread using the
enqueue_and_wait function. The image threads use the dequeue_until
function to limit their lifetime.

After a connection is made and the url is parsed it first checks with
the TQM for a listener with that image id. If it doesn't exist it will
immediately detach a new thread for that image and sleep for a couple
of seconds. The image thread registers as a listener with the TQM and
serves a tiny jpg image as a response to the TQM.

This works perfectly fine except that the request following the thread
starting request from the same client is never answered. Subsequent
requests as well as requests from other clients are handled without
any problems. The strange thing is that the browser will wait until
the image thread finishes and then re-requests the image. If you
tunnel the request through an apache proxy (as I intend to do) it
raises an error. So it seems somehow this thread starting messes with
the (HTTP, TCP/IP?) connection.

I've looked a little bit at the network traffic using wireshark and
did notice that the first request never exchanges a FIN, ACK with the
server. But that stuff is way over my head :-)

I cleaned up my program a bit and pasted it below. It now just tosses
around text strings, but it still shows the same behavior on my
computer (i386 Ubunbtu  feisty, perl 5.8.8). It starts a local server
on port 8080 and handles urls in the form of http://localhost/<number>/<number>
. You can start the program, do a request from your browser and wait
for the answer, then press the reload button. The browser will wait
until the image thread times out (40 seconds), then re-request.

Do you think this is a bug? Should I report this somewhere?

BTW, I worked around this problem by creating a thread starting thread
that listens to another queue so no more threads are started from
within the connection loop. This works fine, but it is a bit of a
hack!

Regards, Arno


Example program:

#!/usr/bin/perl

use strict;
use warnings;

use threads;
use Thread::Queue::Multiplex;

use HTTP::Daemon;
use HTTP::Response;
use HTTP::Status;


$|=1;

my $requestqueue_store = new
Thread::Queue::Multiplex(ListenerRequired=>0);

my $d = HTTP::Daemon->new(Listen=>10,LocalPort=>8080, ReuseAddr=>1) ||
die;
print "Please contact me at: <URL:", $d->url, ">\n";
while (my $c = $d->accept) {
        print "connection!\n";
        while(my $r = $c->get_request) {
                $c->force_last_request;
                if ($r->method eq 'GET' and $r->url->path =~ m/\/(\d+)\/(\d+)\/
{0,1}$/) {
                my $hybid = $1;
                my $featureid = $2;
                print "W-hybid = $hybid, featureid = $featureid\n";

                #do we hava a running thread for this hyb?
                my @subids = $requestqueue_store->get_subscribers();

                if((grep {$_ == $hybid} @subids) == 0) {
                        #spawn new thread
                        print "W- Creating new image thread...";
                        threads->create("image_thread", $hybid)->detach;
                        sleep 2;
                }

                #queue request and wait for response
                my $img_resp = $requestqueue_store->enqueue_and_wait($hybid,
$featureid);
                my $img = $img_resp->{$hybid}->[0];

                my $resp = new HTTP::Response(200);
                $resp->content($img);
                $resp->header('content_type'=>'text/html',
data_lenght=>length($img));
                print "W-Sending data\n";

                $c->send_response($resp);
        }
        else {
                $c->send_error(RC_FORBIDDEN)
        }
        }
        print "W- Closing connection\n";
        $c->close();

}

sub image_thread {
        my $hybid = shift;
        $requestqueue_store->subscribe($hybid);

        my $tid = threads->self->tid;

        print "I-($tid) Testthread for $hybid...";

        print "I-($tid) is Waiting\n";
        while(my $msg = $requestqueue_store->dequeue_until(40)) {
                if(not defined $msg) {
                        print "I-($tid) inactive for 40\n";
                        last;
                }
                my $id = $msg->[0];
                my $featureid = $msg->[1];
                print "I-($tid)-Got request for $featureid, msgid=$id\n";

                my $response = "You requested $featureid, and I ($hybid) 
served!\n";

                #queue the response
                $requestqueue_store->respond($id, $response);
                my $response = "Answer sent";
        }
        print "I-($tid) Exiting thread\n";
        print "I-($tid) cleaned up modules, deregister listener\n";
        $requestqueue_store->unsubscribe();
        print "I-($tid) all done...exiting\n";
}

Reply via email to