多进程你可能很熟悉,也许有一套自己的使用习惯和方法。这东西没有什么权威建议,书上只是给出了基本知识点,至于具体怎么去用,因人而异。nginx在多进程设计方面有很多值得学习和借鉴的东西,我认为是一套比较好的实现方案。你也许认为这东西很简单,是老生常谈的东西了,但是我这里要提醒你一下,俗话道酒是陈的香,越经典的东西越值得去琢磨,不要对自己太自信。善于思考的家伙总是会在一些老的技术上给你许多新鲜的见解,这种牛人你不会没遇到过吧!扯淡罢了,回到正题。
看函数ngx_spawn_process的骨架:
for (s = 0; s < ngx_last_process; s++) { ... } ... /* * 实现异步通知的两个步骤,在nginx事件模型的rtsig机制中会用到 * 参考: */ if (ioctl(ngx_processes[s].channel[0], FIOASYNC, &on) == -1) { ... } if (fcntl(ngx_processes[s].channel[0], F_SETOWN, ngx_pid) == -1) { ... } ... ngx_channel = ngx_processes[s].channel[1]; ... // 当前产生的子进程在ngx_processes数组中的下标 ngx_process_slot = s; /* * 在fork之后,父进程的ngx_processes数组,“传递”给了子进程,但是这时子进程拿到的数组是截至创建该进程之前其他进程的信息。 * 由于子进程是父进程fork得到的,那么在之后父进程的操作结果在子进程中就不可见了。假设当前诞生的是进程1,用p1表示,当父进程 * 创建p5时,那么p2-p5的进程信息在p1中是缺失的,那么p1需要这些信息吗?如果需要的话,该通过什么手段给它呢? * 见ngx_start_worker_processes相关分析 */ ngx_pid = fork(); switch (pid) { ... case 0: ngx_pid = ngx_getpid(); proc(cycle, data); break; default: break; } ... ngx_processes[s].pid = pid; ... if (s == ngx_last_process) { ngx_last_process++; } /* * 父进程,也就是master进程,依次创建work子进程,为了确保ngx_processes数组在子进程间同步,每次创建完一个子进程, * 就通过ngx_pass_open_channel,做一次广播,告诉先前已经创建的子进程: "新进程诞生,注意更新进程数组相关项" * 那么这些子进程又是如何更新这些信息的呢?答案在ngx_worker_process_init中。 */ ngx_start_worker_processes(ngx_cycle_t *cycle, ngx_int_t n, ngx_int_t type) { ngx_int_t i; ngx_channel_t ch; ch.command = NGX_CMD_OPEN_CHANNEL; for (i = 0; i < n; i++) { ch.pid = ngx_processes[ngx_process_slot].pid; ch.slot = ngx_process_slot; ch.fd = ngx_processes[ngx_process_slot].channel[0]; ngx_pass_open_channel(cycle, &ch); } }