首页 > 学院 > 开发设计 > 正文

APUE读书笔记---进程间通信之POSIX共享内存区

2019-11-06 07:52:46
字体:
来源:转载
供稿:网友

APUE读书笔记—进程间通信之POSIX共享内存区

1. 概述

无亲缘关系进程间共享内存区的方法:

内存映射文件(memory-mapped file),有open函数打开,由mmap函数把得到的描述符映射到当前进程地址空间的一个文件。共享内存对象(shared-memory object),由shm_open打开一个POSIX ipC名字(路径名),所返回的描述符由mmap函数映射到当前进程的地址空间。POSIX把两者合称为内存区对象(memory object)

2. shm_open和shm_unlink函数

#include <sys/mman.h>#include <sys/stat.h> /* For mode constants */#include <fcntl.h> /* For O_* constants */int shm_open(const char *name, int oflag, mode_t mode);//返回值:若成功则为非负描述符,若出错则为-1int shm_unlink(const char *name);//返回值:若成功则为0,若出错,返回-1name的命名规则: 必须符合已有的路径名规则(必须最多由PATH_MAX个字节构成,包括结尾的空字节)如果它以斜杠开头,那么对这些函数的不同调用将访问同一个队列。名字中额外的斜杠符的解释由实现定义。为了可移植性,IPC名字必须以一个斜杠开头,并且不能包含其他的斜杠符。oflag参数必须指定O_RDONLY或O_RDWR标志,还可以指定O_CREAT、O_EXCL、O_TRUNC标志。mode参数必须在O_CREAT标志下使用,和open函数类似。shm_unlink函数删除一个共享内存区对象的名字。删除一个name不会影响对其底层支撑对象的现有引用。只是防止后续的open等等函数的调用取得成功。

3. ftruncate和fstate函数

处理mmap时,可以调用ftruncate函数对普通文件或共享内存对象的大小修改。

#include <unistd.h>#include <sys/types.h>int ftruncate(int fd, off_t length);//返回值:若成功则为0,若出错,返回-1

打开一个存在的共享内存区对象时,可以调用fstat来获取有关该对象的信息。

S#include <sys/types.h>#include <sys/stat.h>#include <unistd.h>int fstat(int fd, struct stat *buf);//返回值:若成功,返回0,若出错则为-1

stat结构有12个以上成员,当fd指代一个共享内存区对象时,只含有四个成员信息。

struct stat { mode_t st_mode; /* PRotection */ nlink_t st_nlink; /* number of hard links */ uid_t st_uid; /* user ID of owner */ gid_t st_gid; /* group ID of owner */ };

4. 例子

4.1 创建共享内存对象

#include <stdio.h>#include <stdlib.h>#include <sys/types.h>#include <errno.h>#include <unistd.h>#include <sys/stat.h>#include <sys/mman.h>#include <fcntl.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; struct stat buf; shmid = shm_open("/xyz", O_CREAT | O_RDWR, 0666); if (shmid == -1) ERR_EXIT("shm_open"); printf("shm_open succ/n"); if ((ftruncate(shmid, sizeof(STU))) == -1) ERR_EXIT("ftruncate"); if (fstat(shmid, &buf) == -1) ERR_EXIT("fstat"); printf("size = %ld, mode = %o/n", buf.st_size, buf.st_mode & 07777); close(shmid); return 0;}//先将共享区对象大小用ftruncate修改,然后用fstat读出占的大小

运行结果:

➜ shm_open ./shm_open shm_open succsize = 36, mode = 664//mode为664是因为有umask掩码是002

然后可以在/dev/shm目录中查看到xyz文件

➜ shm ls -l /dev/shm/xyz-rw-rw-r-- 1 menwen menwen 36 3月 3 23:47 /dev/shm/xyz

4.2 写如共享内存区

int main(void){ int shmid; struct stat buf; STU *ptr; shmid = shm_open("/xyz", O_RDWR, 0666); if (shmid == -1) ERR_EXIT("shm_open"); printf("shm_open succ/n"); if (fstat(shmid, &buf) == -1) ERR_EXIT("fstat"); printf("size = %ld, mode = %o/n", buf.st_size, buf.st_mode & 07777); ptr = mmap(NULL, buf.st_size, PROT_WRITE, MAP_SHARED, shmid, 0); if(ptr == MAP_FAILED) ERR_EXIT("mmap"); strcpy(ptr->name, "test"); ptr->age = 20; close(shmid); return 0;}//读写打开xyz文件,mmap函数映射得到内存地址,并且是写保护,写入一个结构的数据。

4.3 读出数据

int main(void){ int shmid; struct stat buf; STU *ptr; shmid = shm_open("/xyz", O_RDWR, 0666); if (shmid == -1) ERR_EXIT("shm_open"); if (fstat(shmid, &buf) == -1) ERR_EXIT("fstat"); printf("size = %ld, mode = %o/n", buf.st_size, buf.st_mode & 07777); ptr = mmap(NULL, buf.st_size, PROT_READ, MAP_SHARED, shmid, 0); if(ptr == MAP_FAILED) ERR_EXIT("mmap"); printf("name = %s, age = %d/n", ptr->name, ptr->age); close(shmid); return 0;}//读写打开xyz文件,mmap函数映射得到内存地址,并且是读保护,读出一个结构的数据。

运行结果:

➜ shm_open ./shm_writesize = 36, mode = 664➜ shm_open ./shm_read size = 36, mode = 664name = test, age = 20//读出和写入相同,或者可以用od命令查看文件内容➜ shm od -c -A d /dev/shm/xyz0000000 t e s t /0 /0 /0 /0 /0 /0 /0 /0 /0 /0 /0 /00000016 /0 /0 /0 /0 /0 /0 /0 /0 /0 /0 /0 /0 /0 /0 /0 /00000032 024 /0 /0 /00000036
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表