[FASTCGI] libfcgi in multi threaded app

Rob rclemley at booksys.com
Mon May 3 13:05:40 EDT 2010


  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.)







More information about the FastCGI-developers mailing list