Re: libfcgi in multi threaded app
Rob <rclemley-/[email protected]> Mon, 03 May 2010 13:19:56 -0500
| Newsgroups | gmane.comp.web.fastcgi.devel |
|---|---|
| Message-ID | <[email protected]> |
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-xGejAJT2w6xVgU18Zptdi0EOCMrvLtNR@public.gmane.org > [mailto:fastcgi-developers-bounces+chapmanm=pixia.com-xGejAJT2w6xVgU18Zptdi8XXUOn6P5/[email protected]] > On Behalf Of Rob > Sent: Monday, May 03, 2010 11:06 AM > To: [email protected] > 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-xGejAJT2w6xVgU18Zptdi0EOCMrvLtNR@public.gmane.org > http://mailman.pins.net/mailman/listinfo.cgi/fastcgi-developers