前面介绍了system v 共享内存的相关知识,现在来稍微看看posix 共享内存 和系列函数。

共享内存简单来说就是一块真正的物理内存区域,可以使用一些函数将这块区域映射到进程的地址空间进行读写,而posix 共享内存与system v 共享内存不同的是它是用虚拟文件系统(tmpfs)实现的,已经挂载在/dev/shm 下面。man 7 shm_overview

下面来看系列函数,编译时候加上 -lrt 选项,即连接librt 库 (实时库)

功能:用来创建或打开一个共享内存对象
原型 int shm_open(const char *name, int oflag, mode_t mode); 
参数
name:共享内存对象的名字,必须以/打头,并且后续不能有其它/ ,形如/somename长度不能超过NAME_MAX(255)
oflag:与open函数类似,可以是O_RDONLY、O_RDWR,还可以按位或上O_CREAT、O_EXCL、O_TRUNC等。
mode:此参数总是需要设置,如果oflag没有指定了O_CREAT,可以指定为0
返回值:成功返回非负整数文件描述符;失败返回-1

注意,不存在所谓的shm_close 函数,可以直接使用close 来关闭文件描述符。

功能:修改共享内存对象大小,shm_open不像shmget一样可以设置共享内存的大小,但可以使用ftruncate 设置大小。
原型 int ftruncate(int fd, off_t length);
参数
fd: 文件描述符
length:长度
返回值:成功返回0;失败返回-1

功能:获取共享内存对象信息
原型
int fstat(int fd, struct stat *buf);
参数
fd: 文件描述符
buf:返回共享内存状态
返回值:成功返回0;失败返回-1

struct stat 可以参考这里

类似 shmctl(, IPC_STAT,);

功能:删除一个共享内存对象
原型 int shm_unlink(const char *name); 
参数
name: 共享内存对象的名字
返回值:成功返回0;失败返回-1

shm_unlink 类似 shmctl(, IPC_RMID, );

功能:将共享内存对象映射到进程地址空间。
原型 void *mmap(void *addr, size_t len, int prot, int flags, int fd, off_t offset);
参数
addr: 要映射的起始地址,通常指定为NULL,让内核自动选择
len:映射到进程地址空间的字节数
prot:映射区保护方式
flags:标志
fd:文件描述符
offset:从文件头开始的偏移量
返回值:成功返回映射到的内存区的起始地址;失败返回-1

前面曾经介绍了mmap 函数 将文件映射到进程地址空间的作用,其实它还可以将共享内存对象映射到进程地址空间,类似shmat的作用,只是传入的文件描述符fd 是shm_open
返回的。同样地,解除映射可以用munmap,类似shmdt 的作用。

下面写几个程序来演示一下:

shm_open.c

 C++ Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
 
#include<stdio.h>
#include<stdlib.h>
#include<sys/ipc.h>
#include<sys/types.h>
#include<unistd.h>
#include<errno.h>
#include<fcntl.h>
#include<sys/stat.h>
#include<sys/mman.h>

#define ERR_EXIT(m) \
    do { \
        perror(m); \
        exit(EXIT_FAILURE); \
    } while(0)

int main(void)
{
    int  shmid;
    shmid = shm_open("/xyz", O_CREAT | O_RDWR, 0666);
    if (shmid == -1)
        ERR_EXIT("shm_open");
    if (ftruncate(shmid, 36) == -1)
        ERR_EXIT("ftruncate");

struct stat buf;
    if (fstat(shmid, &buf) == -1)
        ERR_EXIT("fstat");

printf("size=%ld, mode=%o\n", buf.st_size, buf.st_mode & 0777);
    close(shmid);
    return 0;
}

simba@ubuntu:~/Documents/code/linux_programming/UNP/posix$ ./shm_open 
size=36, mode=664
simba@ubuntu:~/Documents/code/linux_programming/UNP/posix$ ls -l /dev/shm/xyz 
-rw-rw-r-- 1 simba simba 36 Jun 16 15:01 /dev/shm/xyz

即创建了一个36字节的共享内存段,在/dev/shm 目录下。

shm_write.c

 C++ Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
 
#include<stdio.h>
#include<stdlib.h>
#include<sys/ipc.h>
#include<sys/types.h>
#include<unistd.h>
#include<errno.h>
#include<fcntl.h>
#include<sys/stat.h>
#include<sys/mman.h>
#include<string.h>

#define ERR_EXIT(m) \
    do { \
        perror(m); \
        exit(EXIT_FAILURE); \
    } while(0)

typedef struct stu
{
    char name[32];
    int age;
} STU;

int main(void)
{
    int  shmid;
    shmid = shm_open("/xyz", O_RDWR, 0);
    if (shmid == -1)
        ERR_EXIT("shm_open");

struct stat buf;
    if (fstat(shmid, &buf) == -1)
        ERR_EXIT("fstat");

printf("size=%ld, mode=%o\n", buf.st_size, buf.st_mode & 0777);

STU *p;
    p = (STU *)mmap(NULL, buf.st_size, PROT_WRITE, MAP_SHARED, shmid, 0);
    if (p == MAP_FAILED)
        ERR_EXIT("mmap");

strcpy(p->name, "test");
    p->age = 20;

close(shmid);
    return 0;
}

simba@ubuntu:~/Documents/code/linux_programming/UNP/posix$ ./shm_write 
size=36, mode=664
simba@ubuntu:~/Documents/code/linux_programming/UNP/posix$ od -c /dev/shm/xyz 
0000000   t   e   s   t  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0
0000020  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0
0000040 024  \0  \0  \0
0000044

使用mmap 将共享内存映射到进程地址空间,将shmid 传入fd 参数,其余跟文件映射没什么区别,od -c查看可以看到写入的东西。

shm_read.c

 C++ Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
 
#include<stdio.h>
#include<stdlib.h>
#include<sys/ipc.h>
#include<sys/types.h>
#include<unistd.h>
#include<errno.h>
#include<fcntl.h>
#include<sys/stat.h>
#include<sys/mman.h>
#include<string.h>

#define ERR_EXIT(m) \
    do { \
        perror(m); \
        exit(EXIT_FAILURE); \
    } while(0)

typedef struct stu
{
    char name[32];
    int age;
} STU;

int main(void)
{
    int  shmid;
    shmid = shm_open("/xyz", O_RDONLY, 0);
    if (shmid == -1)
        ERR_EXIT("shm_open");

struct stat buf;
    if (fstat(shmid, &buf) == -1)
        ERR_EXIT("fstat");

printf("size=%ld, mode=%o\n", buf.st_size, buf.st_mode & 0777);

STU *p;
    p = (STU *)mmap(NULL, buf.st_size, PROT_READ, MAP_SHARED, shmid, 0);
    if (p == MAP_FAILED)
        ERR_EXIT("mmap");

printf("name=%s age=%d\n", p->name, p->age);
    close(shmid);
    return 0;
}

simba@ubuntu:~/Documents/code/linux_programming/UNP/posix$ ./shm_read 
size=36, mode=664
name=test age=20

即读取到了共享内存的数据,注意,读取数据后共享内存的数据还是存在的,除非被覆盖了。

参考:《UNP》

POSIX 共享内存和 系列函数的更多相关文章

  1. System V 共享内存 和 系列函数

    跟消息队列一样,共享内存也有自己的数据结构,如下: struct shmid_ds { struct ipc_perm shm_perm;    /* Ownership and permission ...

  2. Linux IPC实践(10) --Posix共享内存

    1. 创建/获取一个共享内存 #include <sys/mman.h> #include <sys/stat.h> /* For mode constants */ #inc ...

  3. POSIX共享内存

    DESCRIPTION 共享内存是最快的可用IPC形式.它允许多个不相关(无亲缘关系)的进程去访问同一部分逻辑内存. 如果需要在两个进程之间传输数据,共享内存将是一种效率极高的解决方案.一旦这样的内存 ...

  4. Posix共享内存区

    1.概述 Posix提供了两种在无亲缘关系进程间共享内存区的方法: (1)内存映射文件:先有open函数打开,然后调用mmap函数把得到的描述符映射到当前进程地址空间中的一个文件(上一篇笔记所用到的就 ...

  5. 细说linux IPC(四):posix 共享内存

    [版权声明:尊重原创.转载请保留出处:blog.csdn.net/shallnet 或 .../gentleliu,文章仅供学习交流,请勿用于商业用途]         上一节讲了由open函数打开一 ...

  6. linux c编程:Posix共享内存区

    Posix共享内存区:共享内存是最快的可用IPC形式.它允许多个不相关(无亲缘关系)的进程去访问同一部分逻辑内存.如果需要在两个进程之间传输数据,共享内存将是一种效率极高的解决方案.一旦这样的内存区映 ...

  7. 第三十五章 POSIX共享内存

    POSIX共享内存函数介绍 shm_open 功能: 用来创建或打开一个共享内存对象 原型: int shm_open(const char *name, int oflag, mode_t mode ...

  8. linux网络编程之posix共享内存

    今天继续研究posix IPC对象,这次主要是学习一下posix共享内存的使用方法,下面开始: 下面编写程序来创建一个共享内存: 编译运行: 那posix的共享内存存放在哪里呢?上节中学的posix的 ...

  9. php实现共享内存进程通信函数之_shm

    前面介绍了php实现共享内存的一个函数shmop,也应用到了项目中,不过shmop有局限性,那就是只支持字符串类型的:sem经过我的测试,是混合型,支持数组类型,可以直接存储,直接获取,少了多余的步骤 ...

随机推荐

  1. Terrain tessellation &&Threaded Rendering Vk

    https://github.com/NVIDIAGameWorks/GraphicsSamples/tree/master/samples/es3aep-kepler/TerrainTessella ...

  2. 使用jQuery在上传图片之前实现缩略图预览

    使用jQuery在上传图片之前实现缩略图预览 jQuery代码 01 $("#uploadImage").on("change", function(){ 02 ...

  3. 有关于腾讯地图服务端IP定位接口的获取当前城市的处理

    接口说明:http://apis.map.qq.com/ws/location/v1/ip 说明里面写了ip可以缺省,然并卵,经过测试的到结果并不能获取到当前城市,理由是腾讯ip库的对应ip精度没有定 ...

  4. Java基础(三):修饰符、运算符、循环结构和分支结构

    一.Java修饰符: Java语言提供了很多修饰符,主要分为以下两类:访问修饰符和非访问修饰符.修饰符用来定义类.方法或者变量,通常放在语句的最前端. 1.访问控制修饰符: Java中,可以使用访问控 ...

  5. .NET-WEB网站部署的过程中需要注意的问题

    --部署的网站的文件夹需要有IIS_USER权限(写权限) --部署的网站在外网不能访问:一般是由于防火墙的限制导致的.配置防火墙就可以.

  6. 开学了!这些Linux认证你要知道

    大家好,今天我们将认识一些非常有价值的全球认可的Linux认证.Linux认证是不同的Linux专业机构在全球范围内进行的认证程序.Linux认证可以让Linux专业人才可以在服务器领域或相关公司等等 ...

  7. Cognos由于JAVA_HOME冲突引起的错误假象

    Cognos的安装和配置并不是很复杂,但是对于初次安装的用户来说,还是要注意一些细节,比如JDK问题,今天我们就来阐述一下这个问题 场景1: 作为一个开发人员,很多人是十八般武艺样样精通,难免已经在自 ...

  8. 【python】理想论坛帖子爬虫1.06

    昨天认识到在本期同时起一百个回调/线程后程序会崩溃,造成结果不可信. 于是决定用Python单线程操作,因为它理论上就用主线程跑不会有问题,只是时间长点. 写好程序后,测试了一中午,210个主贴,11 ...

  9. 刀片服务器和磁盘阵列卡(RAID)技术---永和维护(转)

    近期客户需要更换服务器,客户把买好的服务器送来了,原本感觉很小的一个服务器,可当我看到的时候是一个大个的又长又宽,类似机房服务器的那种,后来米老师给大致讲解一番:这个是刀片服务器. 刀片服务器是指在标 ...

  10. 破解OfficeVBA密码的方法

    我自己找到一个office的VBA加密方法,然后再去找一个方法来破解密码,好像有点自相矛盾啊. 如果excel文件是xls或xlm格式(如果不是请转化成此种方法),则可使用以下代码: '移除VBA编码 ...