Posix共享内存区基础知识
来源:互联网 发布:帝国cms验证权限 编辑:程序博客网 时间:2024/05/17 14:28
1. 基本信息
共享内存区是可用IPC中最快的,一旦其映射到共享它的进程的地址空间,进程间的数据场地就不再涉及内核(无需系统调用传递数据)。
普通的客户-服务程序涉及的步骤:
服务端读文件—》服务端写入IPC—》客户端读IPC—》客户端写入文件
而使用共享内存:
服务端将文件读入共享内存对象—》客户端从共享对象写入文件。
2. mmap、munmap和msync函数
#include <sys/mman.h>void *mmap(void *addr, size_t len, int prot,int flags, int fd, off_t offset); //成功返回映射区起始地址,失败返回MAP_FAILED
addr 指定起始地址,一般置为NULL,内核自己选择起始地址;
len 指定映射到调用进程空间的字节数,其从距离文件头offset个字节数开始,一般设为0.
prot 内存映射区的保护由此参数指定,该参数的常见值是代表读写访问的PROT_READ| PROT_WRITE
PROT_READ 数据可读
PROT_WRITE 数据可写
PROT_EXEC 数据可执行
PROT_NONE 数据不可访问
flags 常值指定,MAP_SHARED 或 MAP_PRIVATE这两个必须指定一个
MAP_SHARED 变动是共享的
MAP_PRIVATE 变动是私有的
MAP_FIXED 准确的解释addr参数,可移植程序不应指定
该函数把一个文件或posix共享内存区对象映射到调用进程的地址空间。主要有三个目的:
A. 使用普通文件以提供内存映射I/O
B. 是用特殊文件以提供匿名内存映射
C. 是用shm_open以提供无亲缘关系进程间的Posix共享内存区。
父子进程之间共享内存区的方式是在fork之前指定MAP_SHARED调用mmap。一旦mmap成功返回,fd参数可以被关闭,该操作对于mmap建立的映射关系没有影响。
#include <sys/mman.h>int munmap(void *addr, size_t len);addr 由mmap返回的地址
len 映射区的大小
调用该函数后后再使用这些地址会返回SIGSEGV信号,如果映射区是MAP_PRIVATE标志映射的,若指定MAP_SHARED则调用进程对它所做的变动都会被丢弃。一般内核的虚拟内存算法(硬盘上)与内存映射区(内存中)的同步(有一定同步延迟),若要保证同步需要调用msync函数。
#include <sys/mman.h>int msync(void *addr, size_t len, int flags) //成功0,出错返回-1addr & len 指代整个映射区,不过也可以指定该内存的一个子集
flags 常用以下值,必须指定前两个中的一个,但不可同时指定
MS_ASYNC 执行异步写,等待写操作完成
MS_SYNC 执行同步写,操作由内核排入队列立即返回
MS_INVALIDATE 使用高速缓存的数据失效,与副本不一直的内存数据都将被丢弃
不是所有的文件都能进行内存映射,比如终端或套接字描述符会返回一个错误。
struct shared{sem_t mutex;int count;}shared;int main(int argc, char **argv){int fd , i, nloop;struct shared *ptr;nloop = atoi(argv[2]);fd = open(argv[1],O_RDWR);write(fd, &shared,sizeof(struct shared));ptr = mmap(NULL,sizeof(struct shared), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);close(fd);sem_init(&ptr->mutex, 1, 1);setbuf(stdout, NULL);if(fork() == 0){for(i == 0; i < nloop; i++){sem_wait(&ptr->mutex);printf("child: %d\n, ptr->count++);sem_post(&ptr->mutex);}exit(0);}for( i == 0; i < nloop; i++){sem_wait(&ptr->mutex);printf("parent: %d\n",ptr->count++);sem_post(&ptr->mutex);}exit(0);}
上面的例子中我们需要先open文件(不存在就在文件系统中创建它,然后写一些0以初始化文件。但是,如果是父子进程则可以简化策略。
(1)对于BSD设备,提供"匿名内存映射“,其办法是把mmap的flags参数指定成MAP_SHARED|MAP_ANON,把fd指定为-1,而flag参数被忽略,这样的内存被初始化为0.
int main(int argc, char* argv[]){ int i,nloop; int *ptr; sem_t *mutex; nloop = atoi(argv[1]); ptr = mmap(NULL, sizeof(int), PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANON, -1, 0);}
(2)SVR4提供/dev/zero设备文件,我们open它之后就可以在mmap中使用得到的描述符,从该设备读时返回的字节全为0,写往该设备的任何直接则被丢弃。
int main(int argc, char* argv[]){ int i,nloop; int *ptr; sem_t *mutex; nloop = atoi(argv[1]); fd = open("/dev/zero", O_RDWR); ptr = mmap(NULL, sizeof(int), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);close(fd);}
5. Posix共享内存区
Posix提供了2种在无亲缘关系的进程间共享的内存区的办法:
A. 内存映射文件:open打开,mmap将描述符fd映射到当前进程地址空间(上面提到的第一种方式)
B. 共享内存区对象:由shm_open打开一个IPC名字,将返回的描述符映射到当前进程的地址空间
Posix共享内存区涉及到两个步骤:
首先,使用shm_open打开一个已有或创建一个新的共享内存区对象;然后,使用mmap将其映射到进程的地址空间。传递给shm_open的名字参数可以由希望共享该内存区的任何进程使用。
#include <sys/mman.h>int shm_open(const char *name, int oflag, mode_t mode);//成功返回描述符,失败返回-1int shm_unlink(const char* name);//成功返回描述符,失败返回-1
name 必须以/ 开头
oflag 必须含有O_RDONLY 和 O_RDWR,还可以指定O_CREAT、O_EXCL(若对象已存在,返回EEXIST错误)、O_TRUNCmode S_IWUSR\S_IRUSR\S_IWGRP\S_IRGRP\S_IWOTH\S_IROTH
这里说明一下shm_unlink,该函数仅仅是删除一个共享内存对象的名字,防止后续的open操作,但不会影响对于其底层支撑对象的现有引用,知道该对象的引用全部关闭为止,这是大部分unlink参数的作用。
shm_open默认打开的对象大小为0,我们可以通过ftruncate函数调整普通文件和共享内存区对象的大小:
#include<unistd.h>int ftruncate(int fd, off_t length);对于普通文件,若其长度大于length,则丢弃大于length部分,若长度小于length,则会将文件扩大至length大小,但一般来说扩展文件采用另一种策略:lseek到指定位置,在length-1处写一个字节;
对于一个共享内存区对象:ftruncate将对象设置为length指定大小,在调整大小时并不能保证被初始化为0,尽管标准是这样定义的。
我们还可以同过fstat查看共享内存区对象的信息:
#include <sys/type.h>#include <sys/stat.h>int fstat(int fd, struct stat *buf);简单示例:
struct shmstruct{int count;};sem_t *sem;int main(int argc, char* argv[]){int fd;struct shmstruct *ptr;shm_unlink(argv[1]);fd = shm_open(argv[1], O_RDWR | O_CREAT | O_EXCL ,FILE_MODE);ftruncate(fd,sizeof(struct shmstruct));ptr = mmap(NULL,sizeof(struct shmstruct), PROT_READ|PROT_WRITE, MAP_SHARED, fd ,0);close(fd);sem_unlink(argv[2]);mutex = sem_open(argv[2]);sem_close(mutex);return 0;}
- Posix共享内存区基础知识
- Posix共享内存区
- Posix共享内存区
- Posix共享内存区的基本操作
- Posix共享内存区(chapter 13)
- 简单的Posix共享内存区程序
- UNPv2第十三章:Posix共享内存区
- Posix多线程-共享内存
- posix 基于共享内存
- posix 共享内存
- POSIX 共享内存
- POSIX共享内存
- 关于Posix共享内存
- 【IPC】Posix共享内存区与mmap内存映射
- IPC通信:Posix共享内存
- Linux 多线程编程( POSIX )( 六 )----->代码区 ( 共享内存实例 )
- Linux 多线程编程( POSIX )( 六 )----->共享内存区
- Linux 多线程编程( POSIX )( 六 )----->共享内存区
- 3D重建山雨欲来
- c++深拷贝和浅拷贝
- 控制隐藏和显示android虚拟键和状态栏
- C#中MessageBox用法大全(转)
- C#字符串处理插入(Insert)函数
- Posix共享内存区基础知识
- Python 系列教程
- DISCUZ论坛目录文件说明
- 70分享应用程序
- 常用的一些eclipse快捷键
- Android中LayoutInflater和MenuInflater用法
- ACM并查集浅谈
- 新手程序员之初生牛犊不怕虎
- C++builder中注册表读写