http://wdhdmx.iteye.com/blog/1477218
Official information: http://www.fastcgi.com/devkit/doc/overview.html
Http://www.fastcgi.com/devkit/doc/fastcgi-prog-guide/ap_guide.htm
Http://www.fastcgi.com/devkit/doc/fcgi-devel-kit.htm
0. Background
Content waiting to be communicated is added to the project, so the single request processing time has increased. Single-threaded processing of fcgi wastes CPU and user time, so multiple threads are required to process, reducing user queuing time.
Changing the part of the processing user request from a single thread to multi-threading requires a general understanding of whether the change will affect performance.
The
concludes that multithreading and threading are executed in almost the same way as a single thread, so multithreading does not pose an additional burden. 1. Single Thread processing steps 1.1 A simple single-threaded fcgi request C code #include <fcgi_stdio.h> void main (void) { int count = 0; while (Fcgi_accept () >= 0) { printf ("content-type: text/html\r\n"); printf ("\ r \ n"); printf ("Hello world!<br>\r\n "); printf (" Request number %d. ", count++); } exit ( 0); } 1.2 enters fcgi_accept.
Enter this fcgi_accept () method inside, in the file FCGI_STDIO.C. C code int fcgi_accept (void) { //variable Indicates whether the request is received. Default is Fasle, do not receive requests if (!acceptcalled) { //judge whether it is CGI, the variable is global static, next time will be used. iscgi = fcgx_iscgi (); The //status changes to receive requests. acceptCalled = TRUE; //the end of the request, the value is emptied to assign the initial values. atexit (&fcgi_finish); } else if (iscgi) { // Not the first request, and it's a CGI program. return (EOF); } &NBsp; if (iscgi) { //cgi Initial assignment operation , do not care. ... } else { fcgx_stream *in, *out, * error; //char** string array. FCGX_ParamArray envp; //accept the request, this method is described below int acceptresult = fcgx_accept (&IN,&NBSP;&OUT,&NBSP;&ERROR,&NBSP;&ENVP); //receive failed, return <0, which is why the judgment on the loop is while (fcgi_ Accept () >= 0) if (acceptresult < 0) { return acceptresult; } / /Assign the resulting data to the corresponding output, input, data. FCGI_stdin->stdio_stream = NULL; FCGI_stdin->fcgx_stream = in; FCGI_stdout->stdio_stream = NULL; FCGI_stdout->fcgx_stream = out; FCGI_stderr->stdio_stream = NULL; FCGI_stderr->fcgx_stream = error; environ = envp; } //End return 0; } 1.3 fcgx_acceptWait for the method to receive the request, in FCGIAOO.C.
C code static fcgx_request the_request; int fcgx_accept (fcgx_stream &NBSP;**IN,FCGX_STREAM&NBSP;**OUT,FCGX_STREAM&NBSP;**ERR,FCGX_PARAMARRAY&NBSP;*ENVP) { int rc;//defines the variables that are returned. whether //has been initialized. if (! libinitialized) { rc = fcgx_init (); if (RC) { return rc; } } //receive data, the following introduction rc = fcgx_ Accept_r (&the_request); //assigns a value to the corresponding stream and data. *in = the_request.in; *out = the_request.out; *err = the_request.err; *envp = the_request.envp; return rc; } 1.4 fcgx_accept_r ()
With the fcgiapp.c inside; C code /* *---------------------------------------------------------------------- * * FCGX_Accept_r -- * * from http server receive a new request * Results: * correct return of 0, Error return -1. * Side effects: * * The request is completed via fcgx_accept, the Input,output stream is created, and each is assigned to in * ,out, Err. Create parameter data is removed from Fcgx_getparam and given to ENVP. * do not save pointers and strings, they will be released in Fcgx_finish in the next request. *---------------------------------------------------------------------- */ Int fcgx_accept_r (fcgx_request *reqdataptr) { if (!libinitialized) { return -9998; } //The current reqdata to complete the request. Releases the content, initializes it. fcgx_finish_r (reqdataptr); //while for (;;) { //ipcFd is the conduit of communication between the two sides, in the above Fcgx_finish_ R is assigned a value of-1. if (reqdataptr->ipcfd < 0) { int fail_on_ intr = reqdataptr->flags & fcgi_fail_accept_on_intr; //receive a request, incoming socket, no request will wait here. That's the point, but I can't read it. reqDataPtr->ipcFd = os_accept (Reqdataptr->listen_sock, fail_on_intr, webserveraddresslist); if (reqdataptr->ipcfd < 0) { return (errno > 0) ? (0 - errno) : -9999; } } reqDataPtr->isBeginProcessed = FALSE; reqdataptr->in = newreader (reqdataptr, 8192, 0); fillbuffproc (reqdataptr->in); if (!reqdataptr->isbeginprocessed) { goto tryagain; } { //view the request type. char *roleStr; switch (ReqDataPtr->role) { case FCGI_RESPONDER: roleStr = "Fcgi_role=responder"; break; &NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&Nbsp; case fcgi_authorizer: rolestr = "Fcgi_role=authorizer"; break; case FCGI_FILTER: rolestr = "Fcgi_role=filter"; break; default: goto tryagain; } //creates a space for storing parameter querystring. reqdataptr->paramsptr = newparams (; ) //the request type as a key-value join parameter. putparam (reqDataPtr-> Paramsptr, stringcopy (ROLESTR)); } //reads the input stream in a developed manner (where it stops, whether it needs to skip requests) setreadertype (reqdataptr->in, fcgi_params); //writes the parameter read to the Key=value. if (Readparams (reqdataptr->paramsptr, reqdataptr->in) >= 0) { //jumps out of the loop, or waits for the next request. break; } //releases these intermediate-generated things. Place IPCFD as -1. tryagain: fcgx_free ( reqdataptr, 1); } /* for (;;) */ //assigns the remaining information to the value. Complete the start part of a request. setreadertype (Reqdataptr->in, fcgi_stdin); reqdataptr->out = newwriter (reqdataptr, 8192, fcgi_stdout); reqdataptr->err = newwriter (Reqdataptr, 512, fcgi_stderr ); reqDataPtr->nWriters = 2; reqDataPtr->envp = reqDataPtr->paramsPtr->vec; return 0; } 1.5 Fcgx_finish_r executed before closing the request
in the fcgiapp.c; C Code VOID&NBSP;FCGX_FINISH_R (fcgx_request *reqdataptr) { int close; if (reqdataptr == null) { return; } close = !reqDataPtr->keepConnection; if (reqdataptr->in) { close |= fcgx_fclose (reqdataptr->err); close |= fcgx_fclose (reqdataptr->out); close |= fcgx_geterror (reqdataptr->in); } fcgx_free (reqdataptr, close); }
The basic end, can only understand the process. two multi-threaded requests 2.1 Multi-threaded Request Example
Official website multi-threading example, (HTTP://WWW.FASTCGI.COM/DEVKIT/EXAMPLES/THREADED.C)
Remove the excess output.
C code #define THREAD_COUNT 20 Static int counts[thread_ count]; Static void *doit (void *a) { int rc; FCGX_Request request; fcgx_initrequest (&request, 0, 0); for (;;) { rc = fcgx_accept_r (&request); if (rc < 0) break; fcgx_fprintf (request.out, "content-type: text/html\r\n" "\ r \ n" "<title>FastCGI Hello! "); sleep (2); fcgx_finish_r (&request); } return NULL; } int main (void) { int i; pthread_t id[THREAD_COUNT]; fcgx_init (); for (i = 1; i < thread_count; i++) pthread_create (&id[i], NULL, doit, (void*) i); doit (0); return 0; } 2.2 Methods related to fcgi
In the Main method C code fcgx_init (); Initilize the FCGX library. This was called by fcgx_accept () but must was called by the user when using Fcgx_accept_r ().
In multi-line thread: C code fcgx_request Request;