Nginx에서는 완전한 공유 메모리가 캡슐화되어 ngx_shm_zone_t 데이터 구조로 표현됩니다.
<code><span>typedef</span><span>struct</span> { u_char *addr; <span>// 分配的共享内存的实际地址(这里实际共享内存的分配,根据当前系统可提供的接口,可以调用mmap或者shmget来进行分配,具体的用法,自己man吧)</span> size_t size; <span>// 共享内存的大小</span> ngx_str_t name; <span>// 该字段用作共享内存的唯一标识,能让Nginx知道想使用哪个共享内存</span> ngx_log_t *<span>log</span>; ngx_uint_t exists; <span>/* unsigned exists:1; */</span> } ngx_shm_t; <span>typedef</span><span>struct</span> ngx_shm_zone_s ngx_shm_zone_t; <span>typedef</span> ngx_int_t (*ngx_shm_zone_init_pt) (ngx_shm_zone_t *zone, <span>void</span> *data); <span>struct</span> ngx_shm_zone_s { <span>void</span> *data; ngx_shm_t shm; ngx_shm_zone_init_pt init; <span>// 这里有一个钩子函数,用于实际共享内存进行分配后的初始化</span><span>void</span> *tag; <span>// 区别于shm.name,shm.name没法让Nginx区分到底是想新创建一个共享内存,还是使用已存在的旧的共享内存</span><span>// 因此这里引入tag字段来解决该问题,tag一般指向当前模块的ngx_module_t变量,见:...</span> };</code>
Nginx에서 공유 메모리를 사용하려면 공유 메모리의 이름, 크기 등 공유 메모리 관련 정보(명령어 추가)를 구성 파일에 추가해야 합니다. 공유 메모리 등 따라서 구성 파싱(configuration parsing) 단계에서 해당 명령어를 파싱하면 해당 공유 메모리가 생성된다(이때 공유 메모리를 나타내는 구조체인 ngx_shm_zone_t만 생성된다. 실제 공유 메모리는 ngx_init_cycle(&init_cycle) 이후에 할당된다. 실제 공유 메모리를 할당하고 초기화합니다. 참조:
<code><span>int</span> ngx_cdecl main(<span>int</span> argc, <span>char</span> *<span>const</span> *argv) <span>// 在master进程中</span> { cycle = ngx_init_cycle(&init_cycle); { <span>if</span> (ngx_conf_parse(&conf, &cycle->conf_file) != NGX_CONF_OK) { <span>// 解析配置</span> { 解析到http指令(进入ngx_http_block()) { <span>// 会依次执行</span><span>typedef</span><span>struct</span> { ngx_int_t (*preconfiguration)(ngx_conf_t *cf); <span>/* 执行顺序4 */</span> ngx_int_t (*postconfiguration)(ngx_conf_t *cf); <span>/* 执行顺序8 */</span><span>void</span> *(*create_main_conf)(ngx_conf_t *cf); <span>/* 执行顺序1 */</span><span>char</span> *(*init_main_conf)(ngx_conf_t *cf, <span>void</span> *conf); <span>/* 执行顺序5 */</span><span>void</span> *(*create_srv_conf)(ngx_conf_t *cf); <span>/* 执行顺序2 */</span><span>char</span> *(*merge_srv_conf)(ngx_conf_t *cf, <span>void</span> *prev, <span>void</span> *conf); <span>/* 执行顺序6 */</span><span>void</span> *(*create_loc_conf)(ngx_conf_t *cf); <span>/* 执行顺序3 */</span><span>char</span> *(*merge_loc_conf)(ngx_conf_t *cf, <span>void</span> *prev, <span>void</span> *conf); <span>/* 执行顺序7 */</span> } ngx_http_module_t; 同时,还有个执行顺序<span>4.5</span>: <span>struct</span> ngx_command_s { <span>/* 执行顺序4.5 */</span> ngx_str_t name; ngx_uint_t type; <span>char</span> *(*<span>set</span>)(ngx_conf_t *cf, ngx_command_t *cmd, <span>void</span> *conf); ngx_uint_t conf; ngx_uint_t offset; <span>void</span> *post; }; <span>for</span> (m = <span>0</span>; ngx_modules[m]; m++) { <span>if</span> (module->create_main_conf) {ctx->main_conf[mi] = module->create_main_conf(cf);} <span>if</span> (module->create_srv_conf) {ctx->srv_conf[mi] = module->create_srv_conf(cf);} <span>if</span> (module->create_loc_conf) {ctx->loc_conf[mi] = module->create_loc_conf(cf);} } <span>for</span> (m = <span>0</span>; ngx_modules[m]; m++) { <span>if</span> (module->preconfiguration) {<span>if</span> (module->preconfiguration(cf) != NGX_OK) {} } rv = ngx_conf_parse(cf, NULL); { <span>/* * 指令的解析 * 共享内存配置相关的指令也在这里进行解析 * 详细见: * ngx_shm_zone_t * * ngx_shared_memory_add(ngx_conf_t *cf, ngx_str_t *name, size_t size, void *tag) */</span> } <span>for</span> (m = <span>0</span>; ngx_modules[m]; m++) { <span>if</span> (module->init_main_conf) {rv = module->init_main_conf(cf, ctx->main_conf[mi]);} rv = ngx_http_merge_servers(cf, cmcf, module, mi); } <span>for</span> (m = <span>0</span>; ngx_modules[m]; m++) { <span>if</span> (module->postconfiguration) {<span>if</span> (module->postconfiguration(cf) != NGX_OK)} } } } <span>// in ngx_init_cycle(&init_cycle)</span> line: <span>462</span><span>if</span> (ngx_shm_alloc(&shm_zone[i].shm) != NGX_OK) <span>/* 实际共享内存分配的地方 */</span> line: <span>466</span><span>if</span> (ngx_init_zone_pool(cycle, &shm_zone[i]) != NGX_OK) <span>/* 共享内存管理机制的初始化 * 共享内存的使用涉及另外两个主题: * 1、多进程共同使用时之间的互斥问题 * 2、引入特定的使用方式(slab机制,这在下一个主题:“Nginx源码分析(2)之——共享内存管理之slab机制”中进行介绍),以提高性能 */</span> line: <span>470</span><span>if</span> (shm_zone[i].init(&shm_zone[i], NULL) != NGX_OK) <span>/* 分配之后的初始化 */</span> } } ngx_shm_zone_t * ngx_shared_memory_add(ngx_conf_t *cf, ngx_str_t *name, size_t size, <span>void</span> *tag) { ngx_uint_t i; ngx_shm_zone_t *shm_zone; ngx_list_part_t *part; <span>/* * Nginx中所有的共享内存都以list链表的形式组织在全局变量cf->cycle->shared_memory中 * 在创建新的共享内存之前,会对该链表进行遍历查找以及冲突检测, * 对于已经存在且不存在冲突时,对共享内存直接进行返回并引用 * 存在且不存在冲突:共享内存的名称相同,大小相同,且tag指向的是同一个模块 * 有冲突,则报错 * 否则,重新分配ngx_shm_zone_t,并挂到全局链表cf->cycle->shared_memory中,最后进行结构初始化 * shm_zone = ngx_list_push(&cf->cycle->shared_memory); * 至此: * 仅仅是创建了共享内存的结构体:ngx_shm_zone_t,ngx_shm_zone_t.shm.addr指向的真实共享内存并没有进行实际的分配 */</span> part = &cf->cycle->shared_memory.part; shm_zone = part->elts; <span>for</span> (i = <span>0</span>; <span>/* void */</span> ; i++) { <span>if</span> (i >= part->nelts) { <span>if</span> (part->next == NULL) { <span>break</span>; } part = part->next; shm_zone = part->elts; i = <span>0</span>; } <span>if</span> (name->len != shm_zone[i].shm.name.len) { <span>continue</span>; } <span>if</span> (ngx_strncmp(name->data, shm_zone[i].shm.name.data, name->len) != <span>0</span>) { <span>continue</span>; } <span>if</span> (tag != shm_zone[i].tag) { ngx_conf_log_error(NGX_LOG_EMERG, cf, <span>0</span>, <span>"the shared memory zone \"%V\" is "</span><span>"already declared for a different use"</span>, &shm_zone[i].shm.name); <span>return</span> NULL; } <span>if</span> (size && size != shm_zone[i].shm.size) { ngx_conf_log_error(NGX_LOG_EMERG, cf, <span>0</span>, <span>"the size %uz of shared memory zone \"%V\" "</span><span>"conflicts with already declared size %uz"</span>, size, &shm_zone[i].shm.name, shm_zone[i].shm.size); <span>return</span> NULL; } <span>return</span> &shm_zone[i]; } shm_zone = ngx_list_push(&cf->cycle->shared_memory); <span>if</span> (shm_zone == NULL) { <span>return</span> NULL; } shm_zone->data = NULL; shm_zone->shm.<span>log</span> = cf->cycle-><span>log</span>; shm_zone->shm.size = size; shm_zone->shm.name = *name; shm_zone->shm.exists = <span>0</span>; shm_zone->init = NULL; shm_zone->tag = tag; <span>return</span> shm_zone; }</code>
마지막으로 두 권의 책을 추천합니다:
Gao Qunkai의 "Nginx 심층 분석"
"Nginx에 대한 심층적인 이해 - 모듈 개발 및 아키텍처 분석" by Tao Hui
위 내용은 Nginx 소스 코드 분석(1) - 공유 메모리의 구성, 할당 및 초기화 내용을 포함하여 PHP 튜토리얼에 관심이 있는 친구들에게 도움이 되기를 바랍니다.