当前位置首页 > Apache知识

apache2进程/线程模型

阅读次数:254 次  来源:admin  发布时间:

apache2 有两种进程:主进程( master_main)和子进程( child_main )。

子进程又派生了三种线程:

1、control thread 控制线程。是主线程。负责创建 accept thread, worker threads ,接收和执行 master process 的控制指令。

* events.

2、listener threads 负责处理监听

3、worker threads 负责处理数据交互

// c:\httpd-2.2.17-win32\server\mpm\winnt\mpm_winnt.c

master_main()

apache2 使用 apr_proc_create 来创建一个新的进程。在 windows 下,是调用了 CreateProcessAsUserW 函数。

mpm_winnt.c 是专门针对Windows NT优化的MPM(多路处理模块),它使用一个单独的父进程产生一个单独的子进程,在这个子进程中轮流产生多个线程来处理请求。也就是说 mpm_winnt只能启动父子两个进程, 不能像Linux下那样同时启动多个进程。 mpm_winnt主要通过ThreadsPerChild和MaxRequestsPerChild两个参数来优化Apache,下面详细来说明一下。ThreadsPerChild 这个参数用于设置每个进程的线程数, 子进程在启动时建立这些线程后就不再建立新的线程了. 一方面因为mpm_winnt不能启动多个进程, 所以这个数值要足够大,以便可以处理可能的请求高峰; 另一方面该参数以服务器的响应速度为准的, 数目太大的反而会变慢。因此需要综合均衡一个合理的数值。

mpm_winnt上的默认值是64, 最大值是1920. 这里建议设置为100-500之间,服务器性能高的话值大一些,反之值小一些。

/***********************************************************************

* master_main()

* master_main() runs in the parent process. It creates the child

* process which handles HTTP requests then waits on one of three

* events:

*

* restart_event

* -------------

* The restart event causes master_main to start a new child process and

* tells the old child process to exit (by setting the child_exit_event).

* The restart event is set as a result of one of the following:

* 1. An apache -k restart command on the command line

* 2. A command received from Windows service manager which get

* translated into an ap_signal_parent(SIGNAL_PARENT_RESTART)

* call by code in service.c.

* 3. The child process calling ap_signal_parent(SIGNAL_PARENT_RESTART)

* as a result of hitting MaxRequestsPerChild.

*

* shutdown_event

* --------------

* The shutdown event causes master_main to tell the child process to

* exit and that the server is shutting down. The shutdown event i

* set as a result of one of the following:

* 1. An apache -k shutdown command on the command line

* 2. A command received from Windows service manager which get

* translated into an ap_signal_parent(SIGNAL_PARENT_SHUTDOWN)

* call by code in service.c.

*

* child process handle

* --------------------

* The child process handle will be signaled if the child proce

* exits for any reason. In a normal running server, the signaling

* of this event means that the child process has exited prematurely

* due to a seg fault or other irrecoverable error. For server

* robustness, master_main will restart the child process under thi

* condtion.

*

* master_main uses the child_exit_event to signal the child proce

* to exit.

**********************************************************************/

线程的启动

if ((parent_pid != my_pid) || one_process){

// The child process or in one_process (debug) mode

...

child_main(pconf); ...

}

else{

// A real-honest to goodness parent

...

restart = master_main(ap_server_conf, shutdown_event, restart_event)

...

}

以上,one_process 是对程序启动的命令行参数 ONE_PROCESS 的判断。这个命令行参数在启动时被保存在全局变量 ap_server_config_defines 中。要想以单进程模式运行(没有控制台)httpd,有两种办法:一种是在命令行下使用 -DONE_PROCESS。另一种是在启动后的钩子中直接将变量 写入 ap_server_config_defines。

// ap_hook_post_config( ) 钩子中插入以下代码,

char **new_start_arg

ew_start_arg = (char **)apr_array_push(ap_server_config_defines)

*new_start_arg = "ONE_PROCESS"

需要注意 *new_start_arg 所指向的字串的生命周期。本例中指向一个静态字符串,这个字符串在进程生命周期内有效。如果指向一个栈变量,则可能成为野指针。

void child_main(apr_pool_t *pconf)

{

...

for (i = 0; i < ap_threads_per_child; i++) {

...

child_handles[i] = (HANDLE) _beginthreadex(NULL, (unsigned)ap_thread_stacksize,

worker_main, (void *) i, 0, &tid)

...

} create_listener_thread()

...

}

tatic void create_listener_thread()

{

...

/* Now start a thread per listener */

for (lr = ap_listeners; lr; lr = lr->next) {

if (lr->sd != NULL) {

_beginthreadex(NULL, 1000, winnt_accept,(void *) lr, 0, &tid)

}

}

}

线程的终止:

实战:

只创建一个监听:

场景设计:

将 httpd 配置为多端口监听的情况下, 我们希望能够分辨收到的数据来自哪个端口。httpd 为每个端口创建了一个线程。

ap_listeners()

子进程的主要代码:

child_main 的完整流程 // child.c

HANDLE exit_event

tatic int shutdown_in_progress = 0

tatic int workers_may_exit = 0

tatic PCOMP_CONTEXT winnt_get_connection(PCOMP_CONTEXT context)

{

while (1) {

if (workers_may_exit) {

return NULL

}

}

}

tatic unsigned int __stdcall winnt_accept(void *lr_)

{

while (!shutdown_in_progress) {

Sleep(100)

}

if (!shutdown_in_progress) {

/* Yow, hit an irrecoverable error! Tell the child to die. */

SetEvent(exit_event)

}

ap_log_error(APLOG_MARK, APLOG_INFO, APR_SUCCESS, ap_server_conf,

"Child %d: Accept thread exiting.", my_pid)

return 0

}

void child_main(apr_pool_t *pconf)

{

HANDLE child_events[2]

child_events[0] = exit_event

while (1) {

/* Check to see if the child has been told to exit */

if (WaitForSingleObject(exit_event, 0) != WAIT_TIMEOUT) {

reak

}

/* wait for previous generation to clean up an entry in the scoreboard */

apr_sleep(1 * APR_USEC_PER_SEC)

}

while (1) {

rv = WaitForMultipleObjects(2, (HANDLE *) child_events, FALSE, 1000)

cld = rv - WAIT_OBJECT_0

if (rv != WAIT_TIMEOUT && rv != WAIT_FAILED && cld == 0 ) {

ap_log_error(APLOG_MARK, APLOG_NOTICE, APR_SUCCESS, ap_server_conf,

"Child %d: Exit event signaled. Child process is ending.", my_pid)

reak

}

}

hutdown_in_progress = 1

/* Tell the worker threads to exit */

workers_may_exit = 1

}

上一篇:Fedora11下,在没路由器,存在多个本地连接的情况下,VirtualPC2007共享ADSL上网指南
下一篇:IIS是如何处理ASP.NET请求的