• linux下进程间通信的机制


    今天突然想起了nginx解决惊群的方法,就是在多个进程间利用锁来保证同一时刻只能有一个worker进程在自己的epoll中加入监听的句柄,那么进程间是怎么共享变量的呢,下面就介绍一下共享内存

    共享内存是 Linux 下提供的最基本的进程间通信方法,它通过 mmap 或者 shmgat 系统调用在内存中创建了一块连续的线性地址空间,而通过 munmap 或者 shmdt 系统调用可以释放这块内存。使用共享内存的好处是当多个进程使用同一块共享内存时,在任何一个进程修改了共享内存中的内容后,其他进程通过访问这段共享内存都能够得到修改后的内容。

    虽然 mmap 可以以磁盘文件的方式映射共享内存,但在 Nginx 封装的共享内存操作方法中是没有使用到映射文件功能的。

    Nginx 定义了 ngx_shm_t 结构体,用于描述一块共享内存:

    typedef struct {
        /* 执行共享内存的起始地址 */
        u_char      *addr;
        /* 共享内存的长度 */
        size_t       size;
        /* 这块共享内存的名称 */
        ngx_str_t    name;
        /* 记录日志的 ngx_log_t 对象 */
        ngx_log_t   *log;
        /* 表示共享内存是否已经分配过的标志位,为 1 时表示已经存在 */
        ngx_uint_t   exists; /* unsigned exists:1 */
    }ngx_shm_t;

    操作 ngx_shm_t 结构体的方法有以下两个:

    • ngx_shm_alloc:用于分配新的共享内存;
    • ngx_shm_free:用于释放已经存在的共享内存。

    mmap 系统调用简述

    void *mmap(void *start, size_t length, int prot, int flags, 
                    int fd, off_t offset);

    mmap 可以将磁盘文件映射到内存中,直接操作内存时 Linux 内核将负责同步内存和磁盘文件中的数据:

    • fd 参数就指向需要同步的磁盘文件
    • offset 则代表从文件的这个偏移量开始共享。
    • 当 flags 参数中加入 MAP_ANON 或者 MAP_ANONYMOUS 参数时表示不使用文件映射方式,这时 fd 和 offset 参数就没有意义了,也不需要传递,此时的 mmap 方法和 ngx_shm_alloc 的功能几乎完全相同。
    • length 参数就是将要在内存中开辟的线性地址空间大小。
    • prot 参数则是操作这段共享内存的方式(如只读或可读可写)。
    • start 参数说明希望的共享内存起始映射地址,通常设为 NULL,即由内存选择映射的起始地址。

    MAP_ANON 是 MAP_ANONYMOUS 的同义词,已过时。表示不使用文件映射方式,并且共享内存被初始化为0,因此忽略 mmap 中的 fd 和 offset 参数,但是为了可移植性,当 MAP_ANONYMOUS(或 MAP_ANON)被指定时,fd 应该设置为 -1。

    如下为使用 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;
    }

    当不在使用共享内存时,需要调用 munmap 或者 shmdt 来释放共享内存:

    int munmap(void *start, size_t length);
    • start:指向共享内存的首地址
    • length:表示这段共享内存的长度

    Nginx 的 ngx_shm_free 方法封装了该 munmap 方法:

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

    Nginx 各进程间共享数据的主要方式就是使用共享内存(在使用共享内存时,Nginx 一般是由 master 进程创建,在 master 进程 fork 出 worker 子进程后,所有的进程开始使用这块内存中的数据)。

    Nginx 的共享内存有三种实现:

    • 不映射文件使用 mmap 分配共享内存(即上面的代码)
    • 以 /dev/zero 文件使用 mmap 映射共享内存
    • 用 shmget 调用来分配共享内存
  • 相关阅读:
    python 元类
    python中__init__()、__new__()、__call__()、__del__()用法
    python内置数据结构方法的时间复杂度
    时间复杂度和空间复杂度
    数据结构及算法(1)
    sys模块python
    python中的文本操作
    python 中的os模块
    python 几种不同的格式化输出
    【js】null 和 undefined的区别?
  • 原文地址:https://www.cnblogs.com/wangshaowei/p/10862346.html
Copyright © 2020-2023  润新知