[FASTCGI] libfcgi in multi threaded app

Martin Chapman chapmanm at pixia.com
Mon May 3 13:14:10 EDT 2010


Rob,

So how does this solution account for the fact that FCGX_Accept_r () resets
the stdio global structure each time it's called?  If you are synchronizing
the code between each request, regardless of it's processed on a separate
worker thread then only one request at a time is really being executed. 

Martin


-----Original Message-----
From: fastcgi-developers-bounces+chapmanm=pixia.com at mailman.fastcgi.com
[mailto:fastcgi-developers-bounces+chapmanm=pixia.com at mailman.fastcgi.com]
On Behalf Of Rob
Sent: Monday, May 03, 2010 11:06 AM
To: fastcgi-developers at mailman.pins.net
Subject: Re: [FASTCGI] libfcgi in multi threaded app

  On 05/03/2010 10:27 AM, AlannY wrote:
> I've created a socket via FCGX_OpenSocket. Everything all right.
>
> Then, I'm creating threads (5, for example). In each thread, I'm
> creating a request with FCGX_InitRequest (with socket, created early and
> FCGI_FAIL_ACCEPT_ON_INTR).
>
> Then the main loop starts. In this loop I'm calling FCGX_Accept_r on
> this request. Here is trouble. Some of threads can successfully accept,
> but some of then can't. Return code from FCGX_Accept is -9.

The main thread loop should repeatedly call FCGX_Accept_r().   Requests 
successfully accepted by FCGX_Accept_r() must then be passed off to your 
worker threads for processing.  Therefore, you might choose to 
dynamically allocate an fcgi request structure before calling 
FCGX_Accept_r() and then pass the dynamically allocated request 
structure to an available worker thread.  The worker thread would then 
process the request and then deallocate the request.

The multi-threaded problem is: "how to pass the requests to the worker 
threads?"  Your program  will be simple and graceful if you choose the 
means of a synchronized queue data structure.  In a synchronized queue 
object, all of the thread synchronization is performed upon access to 
get or put items on the queue.   The mutex guards access to the internal 
data.  The conditions NotFull and NotEmpty signal the threads to wake up 
appropriately via the condition primitives: notify_one or notify_all.   
We use C++ and boost::threads to do something like this:

pseudo code for main thread:

     synchronized_queue_class synchronized_queue  #this is the only 
object that must be visible from all threads

     function get_fcgi_request( request )
         request = allocate(sizeof request)
         FCGX_init_request(request ...)
         if FCGX_Accept_r(request) is successful
         then return TRUE
         else return FALSE
         endif
     endfunction

     while get_fcgi_request( request )
         synchronized_queue.Put(request)
     endwhile

pseudo code for worker threads:

     while synchronized_queue.Get(request)
         process(request)
         deallocate(request)
     endwhile

pseudo code for synchronized_queue_class:

     class synchronized_queue_class:
         queue internal_queue
         condition notFull_condition
         condition notEmpty_condition
         mutex    monitor

procedure Put(item):
             scoped_lock(monitor)
             while internal_queue.full()
notFull_condition.wait(monitor)
             internal_queue.put(item)
             notEmpty_condition.notify_one()
         endprocedure

procedure Get(item):
             scoped_lock(monitor)
             while internal_queue.empty:
notEmpty_condition.wait(monitor)
             internal_queue.push(item)
             notFull_condtion.notify_one()
         endprocedure

     endclass

(There are other details in the synchronized queue which should be 
addressed, such as how to shut down the  queue at the end of the program 
and tell the worker threads to exit.)





_______________________________________________
FastCGI-developers mailing list
FastCGI-developers at mailman.fastcgi.com
http://mailman.pins.net/mailman/listinfo.cgi/fastcgi-developers



More information about the FastCGI-developers mailing list