POSIX共享内存

3.3 POSIX共享内存

​ 在Linux中,POSIX共享内存对象驻留在tmpfs伪文件系统中。系统默认挂载在/dev/shm目录下。当调用shm_open函数创建或打开POSIX共享内存对象时,系统会将创建/打开的共享内存文件放到/dev/shm目录下。

​ 创建共享内存的基本步骤是:

  1. 程序执行shm_open函数创建了共享内存区域,此时会在/dev/shm/创建共享内存文件.

    #include <sys/mman.h>
    int shm_open(const char *name, int oflag, mode_t mode);
    /*
    创建或打开一个共享内存,成功返回一个整数的文件描述符,错误返回-1。
    1.name:共享内存区的名字;
    2.oflag标志位: open的标志一样,一般填写O_CREAT|O_TRUNC|O_RDWR。
    3.mode权限位:  open的mode一样
    */

  2. 通过ftruncate函数改变shm_open创建共享内存的大小为页大小sysconf(_SC_PAGE_SIZE)整数倍,如果不执ftruncate函数的话,会报Bus error的错误。

    #include <unistd.h>
    int ftruncate(int fd, off_t length);
    
    /*函数说明:ftruncate()会将参数fd指定的文件大小改为参数length指定的大小。参数fd为已打开的文件描述词,而且必须是以写入模式打开的文件。如果原来的文件大小比参数length大,则超过的部分会被删去。
    返 回  值:0、-1
    错误原因:errno
              EBADF     参数fd文件描述词为无效的或该文件已关闭
              EINVAL    参数fd为一socket并非文件,或是该文件并非以写入模式打开
     */
  1. 通过mmap函数将创建的共享内存文件映射到内存。

    #include <sys/mman.h>
    void* mmap(void* start,size_t length,int prot,int flags,int fd,off_t offset);
    
    /*函数说明:mmap()必须以PAGE_SIZE为单位进行映射。
      start:    映射区的开始地址,设置为0时表示由系统决定映射区的起始地址。
      length:   映射区的长度,长度单位是以字节为单位,不足一内存页按一内存页处理
      prot:     期望的内存保护标志,不能与文件的打开模式冲突。是以下的某个值,可以通过或运算合理地组合在一起
                PROT_EXEC  页内容可以被执行
                PROT_READ  页内容可以被读取
                PROT_WRITE 页可以被写入
                PROT_NONE  页不可访问
      flags:    指定映射对象的类型,映射选项和映射页是否可以共享。它的值可以是一个或者多个以下位的组合体
                MAP_SHARED 与其它所有映射这个对象的进程共享映射空间。对共享区的写入,相当于输出到文件。            直到msync()或者munmap()被调用,文件实际上不会被更新。
                MAP_PRIVATE 建立一个写入时拷贝的私有映射。内存区域的写入不会影响到原文件。这个标志和以           上标志是互斥的,只能使用其中一个。
                MAP_LOCKED 锁定映射区的页面,从而防止页面被交换出内存。
      fd:      有效的文件描述符。
      offset:   被映射对象内容的起点。
      
      成功返回共享内存地址,失败返回MAP_FAILED
    */


  2. 通过munmap卸载共享内存

  3. int munmap(void* start,size_t length);
    /*
    * start:共享内存地址
    * length:共享内存大小
    */
  4. 通过shm_unlink删除内存共享文件

    int shm_unlink(const char *name);
    /*
    *name:内存共享文件
    */

我们用下面的源程序对POSIX共享内存进行测试,如下shmen_write.c:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/file.h>
#include <sys/mman.h>
#include <sys/wait.h>
void error_print(char *msg)
{
        perror(msg);
        exit(-1);
}

int main (int argc, char *argv[])
{
        int ret, i;
        const char *memname = "/mymem";
        size_t mem_size = sysconf(_SC_PAGE_SIZE);
        int fd = shm_open(memname, O_CREAT|O_TRUNC|O_RDWR, 0666);
        if (fd == -1)
            error_print("shm_open");
        ret = ftruncate(fd, mem_size);
        if (ret != 0)
             error_print("ftruncate");
  
        void *ptr = mmap(0, mem_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
        if (ptr == MAP_FAILED)
             error_print("MMAP");
        close(fd);
        for(i = 0; i < 20; i++)
        {
            sprintf((char*)ptr, "data %d", i);
            printf("write data %s\n", (char*)ptr);
        }
        ret = munmap(ptr, mem_size);
        if (ret != 0)
             error_print("munmap");
        ret = shm_unlink(memname);
        if (ret != 0)
             error_print("shm_unlink");
        return 0;
}

编译程序shmen_write.c

gcc shmen_write.c -o shmen_write -lrt

shmen_read.c

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/file.h>
#include <sys/mman.h>
#include <sys/wait.h>
void error_print(char *msg)
{
        perror(msg);
        exit(-1);
}

int main (int argc, char *argv[])
{
        int ret, i;
        const char *memname = "/mymem"; //共享内存文件以/开头,可以更好兼容不同系统
        struct stat statbuf;
        size_t mem_size = 2 * sysconf(_SC_PAGE_SIZE);
        int fd = shm_open(memname, O_CREAT|O_TRUNC|O_RDWR, 0666);
        if (fd == -1)
            error_print("shm_open");
        ret = ftruncate(fd, mem_size);
        if (ret != 0)
             error_print("ftruncate");

        void *ptr = mmap(0, mem_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
        if (ptr == MAP_FAILED)
             error_print("MMAP");
        close(fd);

        for(i = 0; i < 20; i++)
        {
            printf("read data %s\n", (char*)ptr);
            sleep(1);
        }
        ret = munmap(ptr, mem_size);
        if (ret != 0)
             error_print("munmap");
        ret = shm_unlink(memname);
        if (ret != 0)
             error_print("shm_unlink");
        return 0;
}

编译程序shmen_read.c

gcc shmen_read.c -o shmen_read -lrt

先运行shmem_write,再运行shmem_read.

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值