linux进程间通信--共享内存(POSIX 版本)

linux进程间通信–共享内存(POSIX 版本)

System V共享内存模型使用的是key和标识符,这与标准的UNIX I/O模型使用文件名和描述符的做法不一致。这种差异导致System V共享内存段需要一整套全新的系统调用和命令。由于这些潜在的缺点,因此POSIX标准又重新定义了共享内存API。

共享内存的使用:共享内存被映射到进程的虚拟地址空间之后,就可以跟正常的进程空间内存一样进行各种操作了。

其他说明:

  1. 共享内存并未提供同步机制。所以我们通常需要用其他的机制来同步对共享内存的访问,例如信号量.
  2. 使用了POSIX共享内存函数,链接时要用到-lrt库.
  3. 使用POSIX标准接口shm_open()创建的共享内存对象,可将它认为特殊的文件,可以使用文件操作的相关接口。如修改权限fchmod().
  4. Linux中一般将共享内存创建的文件放在/dev/shm目录下。

共享内存的相关接口函数如下:

#include <fcntl.h>
#include <sys/stat.h>
#include <sys/mman.h>
int shm_open(const char *name, int oflag, mode_t mode);
/*
 * 创建和打开一个新的共享内存对象或打开一个已创建好的对象
 * name :共享内存对象的文件名称.如`/sh_mem1`.由`/`开始,并且只能有一个`/`
 * oflag:
    * O_CREAT: 如果不存在则创建,如果存在在返回创建好的文件描述符。
    * O_EXCL : 配合O_CREAT使用,只有不存在时才创建。存在时返回失败
    * O_RDONLY:只读
    * O_RDWR:  读写
    * O_TRUNC: 如果共享内存对象已经存在,则将其截断为零字节。
 * mode :权限。打开一个已经存在的共享内存时,权限设置为0.
 * return:if true:返回文件描述符。if false:-1.errno值如下:
    * EEXIST:使用了O_EXCL,且文件已经存在
    * EINVAL:name名称不符合要求。
*/

#include <sys/mman.h>
int shm_unlink(const char *name);
/*
 * 创建和打开一个新的共享内存对象或打开一个已创建好的对象
 * name :共享内存对象的文件名称
 * return:if true:返回文件描述符。if false:-1.
    * ENOENT:对象不存在
*/

除了上面的两个专门的共享内存API.一般也要使用到mmap(),fstat(),ftruncate()以及其他的文件操作函数。下面仅简单的介绍,详细请参考具体章节。

#include <sys/mman.h>
void *mmap(void *addr, size_t len, int prot, int flags,int fildes, off_t off);
/*
 * 在进程的地址空间和内存对象之间建立映射。
 * addr: 将文件映射到进程空间指定地址,可以为 NULL,此时系统将自动分配地址。
 * length: 要映射的大小。
 * prot: 映射的访问权限。
    * PROT_EXEC: 页面可执行。
    * PROT_READ: 页面可读。
    * PROT_WRITE: 页面可写。
    * PROT_NONE: 页面不可访问。
 * flags:
    * MAP_SHARED: 共享内存的方式。
 * fildes: 文件描述符,这里为shm_open()函数返回的值。
 * offset: 指定从文件的哪一部分开始映射,必须是内存页的整数倍,通常为 0。
 * return:if true:返回文件描述符。if false:-1.
    * ENOENT:对象不存在
*/

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
int fstat(int fd, struct stat *statbuf);
/*
 * 用于查询文件的信息
 * fd :文件描述符
 * statbuf:用于返回的文件信息buff.
 * return:if true:返回文件描述符。if false:-1.
*/

#include <unistd.h>
#include <sys/types.h>
int ftruncate(int fd, off_t length);
/*
 * 将文件截断为指定长度。用于重新设置文件的大小。
 * fd :文件描述符
 * length:要设定的长度
 * return:if true:返回文件描述符。if false:-1.
*/

共享内存创建与删除例程:

#include <unistd.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>

int main(void)
{
    const char *shm_name = "/sh_mem1";
    const int shm_size = 1024;

    //共享内存创建,创建后在文件系统中可以找到(/dev/shm)
    int shmfd = shm_open(shm_name, O_CREAT | O_RDWR, 0666);
    if(shmfd == -1){
        printf("shm_open error(%d)\n",errno);
        exit(1);
    }

    //创建成功后,别的进程也可以通过"/sh_mem1"来获取共享内存。如
    //int shmfd = shm_open("/sh_mem1", O_RDONLY, 0);

    //2. 设置共享内存的大小
    if (ftruncate(shmfd, shm_size) == -1){
        printf("ftruncate error(%d)\n",errno);
        exit(1);
    }

    //2.5 或者使用fstat获取内存大小
    struct stat buf;
    if(fstat(shmfd,&buf) == -1){
        printf("fstat error(%d)\n",errno);
        exit(1);
    }
    printf("shm size:(%ld)\n",buf.st_size);

    //3. 映射到进程空间
    char *addr = mmap(NULL, shm_size, PROT_READ | PROT_WRITE, MAP_SHARED, shmfd, 0);

    //4. 就可以对addr进行正常的读写操作了。如
    strcmp(addr,"hello word");

    //5. 关闭共享内存的文件描述符。但并不影响map后addr的操作
    close(shmfd);

    //6. 可以通多addr对共享内存继续操作

    //7. 取消映射
    munmap(addr, shm_size);

    //8. 删除共享内存
    if (shm_unlink(shm_name) == -1){
        printf("shm_unlink error(%d)\n",errno);
        exit(1);
    }
    exit(0);
}

关于技术交流

此处后的文字已经和题目内容无关,可以不看。
qq群:825695030
微信公众号:嵌入式的日常
如果上面的文章对你有用,欢迎打赏、点赞、评论。二维码

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

theboynoName

感谢鼓励

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值