</pre><span style="font-size:18px"></span><p></p><p> <span style="white-space:pre"></span>共享内存是linux下提供的最基本的进程间通信方法,它通过mmap或者shmget系统调用在内存中创建了一块连续的线性地址空间,而通过munmap和shmdt系统调用可以释放这块内存.使用共享内存的好处是当多个进程使用同一块共享内存时,在任何一个进程修改了共享内存中的内容后,其他进程通过访问这段共享内存都能够得到修改后的内容.为了支持跨平台,nginx提供了三种共享内存的实现,分别为不映射文件使用mmap分配共享内存,以/dev/zero文件使用mmap映射共享内存,用shmget调用来分配共享内存 </p><p>头文件源码解析:</p><pre name="code" class="cpp">
typedef struct {
u_char *addr; //指向共享内存的起始地址
size_t size; //共享内存的长度
ngx_str_t name; //这块共享内存的名称
ngx_log_t *log; //记录日志的ngx_log_t对象
ngx_uint_t exists; /* unsigned exists:1; *///表示共享内存是否已经分配过的标志为,为1时表示已经存在
} ngx_shm_t;
ngx_int_t ngx_shm_alloc(ngx_shm_t *shm); //分配共享内存
void ngx_shm_free(ngx_shm_t *shm); //释放已经存在的共享内存</span>
实现文件源码解析:
#include <ngx_config.h>
#include <ngx_core.h>
//mmap函数详细知识可看apue中文第三版p423
#if (NGX_HAVE_MAP_ANON) //不映射文件用mmap分配共享内存
//若mmap函数参数中的flags参数加入MAP_ANON,表示不使用文件映射方式,fd参数和offset参数没有意义,此时mmap方法和ngx_shm_alloc的功能几乎一样
ngx_int_t
ngx_shm_alloc(ngx_shm_t *shm)
{
//开辟一块shm->size大小的内存,首地址存放在shm-addr中,同时可读写
shm->addr = (u_char *) mmap(NULL, shm->size,
PROT_READ|PROT_WRITE,
MAP_ANON|MAP_SHARED, -1, 0);
if (shm->addr == MAP_FAILED) { //申请失败
ngx_log_error(NGX_LOG_ALERT, shm->log, ngx_errno,
"mmap(MAP_ANON|MAP_SHARED, %uz) failed", shm->size);
return NGX_ERROR;
}
return NGX_OK;
}
void
ngx_shm_free(ngx_shm_t *shm) //释放共享内存
{
//使用ngx_shm_t中的shm->addr和shm->size参数释放共享内存
if (munmap((void *) shm->addr, shm->size) == -1) {
ngx_log_error(NGX_LOG_ALERT, shm->log, ngx_errno,
"munmap(%p, %uz) failed", shm->addr, shm->size);
}
}
#elif (NGX_HAVE_MAP_DEVZERO) //以/dev/zero文件使用mmap映射共享内存
ngx_int_t
ngx_shm_alloc(ngx_shm_t *shm)
{
ngx_fd_t fd;
fd = open("/dev/zero", O_RDWR);//以读写方式打开文件
if (fd == -1) { //打开失败
ngx_log_error(NGX_LOG_ALERT, shm->log, ngx_errno,
"open(\"/dev/zero\") failed");
return NGX_ERROR;
}
//申请内存,内存地址为shm->addr,大小为shm->size,可读写
shm->addr = (u_char *) mmap(NULL, shm->size, PROT_READ|PROT_WRITE,
MAP_SHARED, fd, 0);
//申请出错
if (shm->addr == MAP_FAILED) {
ngx_log_error(NGX_LOG_ALERT, shm->log, ngx_errno,
"mmap(/dev/zero, MAP_SHARED, %uz) failed", shm->size);
}
//关闭文件失败
if (close(fd) == -1) {
ngx_log_error(NGX_LOG_ALERT, shm->log, ngx_errno,
"close(\"/dev/zero\") failed");
}
//返回是否成功标志
return (shm->addr == MAP_FAILED) ? NGX_ERROR : NGX_OK;
}
void
ngx_shm_free(ngx_shm_t *shm) //释放内存
{
if (munmap((void *) shm->addr, shm->size) == -1) {
ngx_log_error(NGX_LOG_ALERT, shm->log, ngx_errno,
"munmap(%p, %uz) failed", shm->addr, shm->size);
}
}
#elif (NGX_HAVE_SYSVSHM) //用shmget调用来分配共享内存
#include <sys/ipc.h>
#include <sys/shm.h>
ngx_int_t
ngx_shm_alloc(ngx_shm_t *shm)
{
int id;
//创建一个新的共享存储段,返回共享存储id
id = shmget(IPC_PRIVATE, shm->size, (SHM_R|SHM_W|IPC_CREAT));
//创建失败
if (id == -1) {
ngx_log_error(NGX_LOG_ALERT, shm->log, ngx_errno,
"shmget(%uz) failed", shm->size);
return NGX_ERROR;
}
ngx_log_debug1(NGX_LOG_DEBUG_CORE, shm->log, 0, "shmget id: %d", id);
//进程调用shmat将此段共享内存链接到它的地址空间,成功返回共享存储段的指针
shm->addr = shmat(id, NULL, 0);
//失败
if (shm->addr == (void *) -1) {
ngx_log_error(NGX_LOG_ALERT, shm->log, ngx_errno, "shmat() failed");
}
//从系统中删除此共享存储段?????为什么要删除?问徐.....?因为上一个操作失败了,所以删除这段共享内存?????
if (shmctl(id, IPC_RMID, NULL) == -1) {
ngx_log_error(NGX_LOG_ALERT, shm->log, ngx_errno,
"shmctl(IPC_RMID) failed");
}
//返回标志
return (shm->addr == (void *) -1) ? NGX_ERROR : NGX_OK;
}
void
ngx_shm_free(ngx_shm_t *shm) //释放内存
{
//这并不从系统中删除其标识符及其相关数据结构,直到某个进程调用shmctl删除它
if (shmdt(shm->addr) == -1) {
ngx_log_error(NGX_LOG_ALERT, shm->log, ngx_errno,
"shmdt(%p) failed", shm->addr);
}
}