nginx進程間的通信機制源碼分析(一)----共享內存

</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);
    }
}



發佈了25 篇原創文章 · 獲贊 1 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章