0.背景
在项目中加入了等待通讯的内容,所以原来单个请求处理时间增加了。单线程处理的fcgi就会浪费CPU和用户时间,所以需要多线程来处理,减少用户排队时间。
将处理用户请求的部分从单线程变为多线程,需要大概了解改动会不会影响性能。
得到的结论是:多线程和单线程在执行的流程和使用方法几乎一样,所以多线程不会带来额外的负担。
1.单线程的处理步骤
1.1一个简单的单线程fcgi请求
-
#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进入FCGI_Accept。
进入这个 FCGI_Accept() 方法里面,在文件fcgi_stdio.c里。
-
int FCGI_Accept(void)
-
{
-
-
if(!acceptCalled) {
-
-
isCGI = FCGX_IsCGI();
-
-
acceptCalled = TRUE;
-
-
atexit(&FCGI_Finish);
-
} else if(isCGI) {
-
-
return(EOF);
-
}
-
if(isCGI) {
-
-
...
-
} else {
-
FCGX_Stream *in, *out, *error;
-
-
FCGX_ParamArray envp;
-
-
int acceptResult = FCGX_Accept(&in, &out, &error, &envp);
-
-
if(acceptResult < 0) {
-
return acceptResult;
-
}
-
-
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;
-
}
-
-
return 0;
-
}
1.3 FCGX_Accept (&in, &out, &error, &envp)
等待接收请求的方法,在fcgiaoo.c里。
-
static FCGX_Request the_request;
-
-
int FCGX_Accept(FCGX_Stream **in,FCGX_Stream **out,FCGX_Stream **err,FCGX_ParamArray *envp)
-
{
-
int rc;
-
-
if (! libInitialized) {
-
rc = FCGX_Init();
-
if (rc) {
-
return rc;
-
}
-
}
-
-
rc = FCGX_Accept_r(&the_request);
-
-
*in = the_request.in;
-
*out = the_request.out;
-
*err = the_request.err;
-
*envp = the_request.envp;
-
-
return rc;
-
}
1.4 FCGX_Accept_r (),同在fcgiapp.c里面;
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
int FCGX_Accept_r(FCGX_Request *reqDataPtr)
-
{
-
if (!libInitialized) {
-
return -9998;
-
}
-
-
-
FCGX_Finish_r(reqDataPtr);
-
-
for (;;) {
-
-
if (reqDataPtr->ipcFd < 0) {
-
int fail_on_intr = reqDataPtr->flags & FCGI_FAIL_ACCEPT_ON_INTR;
-
-
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;
-
}
-
{
-
-
char *roleStr;
-
switch(reqDataPtr->role) {
-
case FCGI_RESPONDER:
-
roleStr = "FCGI_ROLE=RESPONDER";
-
break;
-
case FCGI_AUTHORIZER:
-
roleStr = "FCGI_ROLE=AUTHORIZER";
-
break;
-
case FCGI_FILTER:
-
roleStr = "FCGI_ROLE=FILTER";
-
break;
-
default:
-
goto TryAgain;
-
}
-
-
reqDataPtr->paramsPtr = NewParams(30);
-
-
PutParam(reqDataPtr->paramsPtr, StringCopy(roleStr));
-
}
-
-
SetReaderType(reqDataPtr->in, FCGI_PARAMS);
-
-
if(ReadParams(reqDataPtr->paramsPtr, reqDataPtr->in) >= 0) {
-
-
break;
-
}
-
-
-
TryAgain:
-
FCGX_Free(reqDataPtr, 1);
-
-
}
-
-
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 (reqDataPtr),在fcgiapp.c里;
-
void 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);
-
}
基本结束了,只能看懂流程。
二 多线程的请求
2.1多线程请求例子
官网多线程的例子,(http://www.fastcgi.com/devkit/examples/threaded.c)
去掉多余的输出。
-
#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和fcgi有关的方法
在main方法里
-
FCGX_Init();
-
Initilize the FCGX library. This is called by FCGX_Accept()
-
but must be called by the user when using FCGX_Accept_r().
在多线程里:
-
FCGX_Request request;
-
FCGX_InitRequest(&request, 0, 0);
-
while(){
-
rc = FCGX_Accept_r(&request);
-
FCGX_FPrintF(request.out,"");
-
FCGX_Finish_r(&request);
-
}
FCGI单线程环境和多线程环境下的例子
原文:http://blog.csdn.net/nyist327/article/details/42968521