[FASTCGI] libfcgi in multi threaded app

Rob rclemley at yahoo.com
Mon May 3 14:19:56 EDT 2010


  FCGX_Accept_r() operates only on the "FCGX_Request *reqDataPtr".  I 
cannot find where FCGX_Accept_r() resets the stdio global structure,  
though I do see this being done in FCGX_Accept(), which uses global 
variables and as such is a no-no for multi-threaded apps.

A *new* FCGX_Request is allocated before each and every call to 
FCGX_Accept_r().  Once a request has been accepted, then the 
FCGX_Request structure is passed to a worker thread.  After processing, 
the worker thread Finishes and deallocates the FCGX_Request structure.  
We use only the FastCGI thread-safe function calls.

I've got hundreds of apache2 VirtualHosts, each running a multi-threaded 
FastCgiExternalServer, high traffic day-in and day-out with no 
multi-thread synchronization or IO problems.

I cannot guarantee that this thing is doing exactly what I think it's 
doing, but it sure seems to work in practice, as well as in theory.

In reality, only one data-stream can pass through the network interface 
at one time.  The fact is, because each worker thread accesses only it's 
own FCGX_Request structure, several requests to a virtual host *appear* 
to be processed simultaneously.

Rob


On 05/03/2010 12:14 PM, Martin Chapman wrote:
> 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