[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