IPC 共享内存

共享内存(Shared Memory)是最简单的进程间通信方式,它允许多个进程访问相同的内存,一个进程改变其中的数据后,其他的进程都可以看到数据的变化。

共享内存是进程间最快速的通信方式:
①进程共享同一块内存空间。
②访问共享内存和访问私有内存一样快。
③不需要系统调用和内核入口。
④不造成不必要的内存复制。

内核不对共享内存的访问进行同步,因此程序员必须自己提供同步。

使用共享内存:
①某个进程分配内存段。
②使用这个内存段的进程要连接(attach)这个内存段。
③每个进程使用完共享内存段后,要分离(detach)这个内存段。
④在某个地方,必须有一个进程来销毁这个内存段。

Linux的内存模型:
①每个进程的虚拟内存被分为页(page)。
②每个进程维护自己的内存地址到虚拟内存页之间的映射。
③实际的数据存在于进程的内存地址上。
④尽管每个进程有自己的地址空间,多个进程的映射还是可以指向相同的页。

所有的共享内存段的大小,都是Linux内存页大小的整数倍。
Linux的页大小是4KB,不过程序员应该使用getpagesize函数来获得这个值。

 

 

分配:shmget

函数原型:shmget(key_t key, int size, int shmflg);

①:shmget用来取得参数key所关联的内存识别代码。如果参数key为IPC_PRIVATE,则会建立新的共享内存,大小是由size来决定的,

实际分配的字节数会舍弃多余部分到页大小的整数倍。

②:如果参数key不是IPC_PRIVATE,也不是已经建立的IPC key, 那么系统会根据shmflg是否有IPC_CREAT位(shmflg | IPC_CREAT)

为真来决定IPC key为参数的共享内存。

③:如果参数包含了IPC_CREAT 和 IPC_EXECL位, 那么如果key标识的共享内存已经存在, 那么会报EEXIST的错误。

④:参数也用来决定共享内存的存取权限, 相当于open()的 mode参数。

 

内存共享attach:shmat

函数原型: void* shmat(int shmid, const void* shmaddr, int shmflg);

①:shmat()用来将参数shmid指定的共享内存和目前进程相连(attach)

②:在经过fork()后, 子进程将继承已连接的共享内存地址,

③:在经过exec()函数后, 已连接的共享内存地址会自动脱离(detach)

④:进程结束后,已连接的共享内存会自动脱离

 

 

脱离:shmdt

函数原型:shmdt(const void *shmaddr);

①:shmdt()用来脱离先前shmat()过的共享内存。

 

 

控制共享内存的操作 shmctl

函数原型:shmctl(int shmid, int cmd, struct shmid_ds *buf);

①:参数cmd 有下面几种操作

    1:IPC_STAT:把共享内存的 shmid_ds的结构copy到 buf 中。

    2:IPC_SET: 把参数buf所指的shmid_ds结构中的 shm_perm.uid, shm_perm.gid, shm_perm.mode 拷贝到共享内存的

shmid_ds结构中。

    3:IPC_RMID:删除共享内存和其数据结构。

 

 

看例子:

 

typedef struct {
    u_char      *addr;
    size_t       size;
    ngx_log_t   *log;
} ngx_shm_t;

 

ngx_int_t
ngx_shm_alloc(ngx_shm_t *shm)
{
    int  id;
/* 用ipc_private 来新建共享内存 */
    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,那么在这个共享内存中的shmid_ds 结构中的shm_nattach就会加一 */
    shm->addr = shmat(id, NULL, 0);

    if (shm->addr == (void *) -1) {
        ngx_log_error(NGX_LOG_ALERT, shm->log, ngx_errno, "shmat() failed");
    }

 

/* 只有在id所标识的共享内存中的shmid_ds结构中的shm_nattach为0的情况下才能被删除。否者无效*/
    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)
{

  /* 每次有进程shmdt,那么在这个共享内存中的shmid_ds 结构中的shm_nattach就会减一 */
    if (shmdt(shm->addr) == -1) {
        ngx_log_error(NGX_LOG_ALERT, shm->log, ngx_errno,
                      "shmdt(%p) failed", shm->addr);
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值