一.POSIX共享内存的实现
-----------------------------------------------------------------------------
共享内存是在进程间共享某一块内存。是最快一种ipc通信机构。其中posix共享内存机制 它主要是通过内存映射(mmap)机制来实现的。
在进程间共享内存使用如下固定步骤:
1.创建一个共享内存
int shm_open(const char *name, int oflag, mode_t mode);
name是共享内存名字,各个进程通过名字来找到同一块内存.
oflag,是这个内存属性。类似于文件属性。使用O_RDWR/O_RDONLY/O_CREAT,第一次创建共享内存必须带O_CREAT标志位。
mode,是权限代码。
当其打开成功是会在建立一个虚拟的文件 /dev/shm/shm.XXXX,其中XXXX是name的名字
例: int fd = shm_open("test",O_RDWR,666);
将会创建 /dev/shm/shm.test文件。
shm_open成功后,将返回一个文件描述符fd.你可以理解是在内核的中分配一段空间,并分配一个fd号给应用程序使用。
这里要注意,如果一个进程已经创建一个共享内存,后面其它的进程打开这个共享内存只需要用
shm_open(name,flag,0); //而且
2.设置内存大小。
int ftruncate(int fd, off_t length);
ftruncate操作的fd即可是一个文件open后的fd,也可是shm_open打开的fd .
普通文件将会被ftruncate强行设为length大小(不够加0空间,超过则被截断
如果共享内存,将表示把共享内存设为length大小.
如果设置 ftruncate返回0
3.用mmap 眏射到进程空间当中某一个地址上
void *mmap(void *start, size_t length, int prot, int flags,
int fd, off_t offset);
start是表示开始映射的物理地址,如果为NULL表示由内核自行选择合适空间来分配。
length是内存的大小,一般是和第二步的同一大小。
prot 是共享内存属性。它有如下值
PROT_EXEC 分配空间可执行
PROT_READ 分配空间可读
PROT_WRITE 可写
PROT_NONE 禁止访问,一般为省事,都设为 PROT_READ|PROT_WRITE
flags 是共享内存的标志位,它有如下取值
MAP_FIXED ,内存固定大小,不能超过一页。如果超过将mmap失败.
MAP_SHARED ,在多个进程间共享这一内存
MAP_PRIVATE, 只供本进程使用。
fd 是shm_open或open创建文件的描述符.
offset 是在共享内存或文件中的偏移量。一般是0
如果映射成功,将会返回一个进程内部地址。对这个地址访问即是对内核共享内存的访问。这个地址位于堆和栈的空闲区。
如果失败,将返回MAP_FAILED (它等于 (void *)-1)
到mmap后,对共享内存的操作就跟与普通内存没有什么区别了。如使用memcpy/memset等操作.
如果结束的对共享内存使用,即可采用接下两步.
4.munmap解除当前进程对这块共享映射。
int munmap(void *start, size_t length);
start是映射的进程内地址,lenght是内存的长度
如果映射是文件,它还有存盘功能。
5.从内核清除共享内存
int shm_unlink(const char *name);
name是共享内存名字,如果有多个进程打开这个内存,只有最后使用进程调用shm_unlink,这个共享内存才会真正清除掉。
二.POSIX共享内存实现代码
---------------------------------------------------------------------------
- #include <unistd.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <fcntl.h>
- #include <signal.h>
- #include <sys/mman.h> /* for mmap,shm_open */
- #include <string.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <errno.h>
- #define PRINT_INTX(e) printf("%s=0x%X\n",#e,e)
- typedef struct mmap_fd{
- int fd; /* 打开后的文件描述符*/
- void * base; /* 在进程内部的地址*/
- char * name; /* 共享内存名字 */
- int len ; /* 共享内存长度 */
- int offset; /* fd中的偏移量*/
- }MMAP_FD;
- #define MMAP_ADDR(p) (p)->base
- MMAP_FD * shm_map(char * name,int len,int offset)
- {
- MMAP_FD * p_fd;
- void * base;
- int fd;
- //第一步:创建一个共享内存
- fd = shm_open(name,O_CREAT|O_EXCL|O_RDWR,666);
- if(fd == -1)
- {
- if(errno == EEXIST)
- {
- fd = shm_open(name,O_RDWR,666);
- }
- }
- if(fd == -1)
- {
- perror("shm_open");
- return NULL;
- }
- //第二步:设置内存大小
- if(ftruncate(fd,len) == -1)
- {
- perror("ftruncate");
- shm_unlink(name);
- return NULL;
- }
- //第三步,将内核中共享内存映射到进程空间之上
- //void *mmap(void *start, size_t length, int prot, int flags,
- // int fd, off_t offset);
- base = mmap(NULL,len,PROT_READ | PROT_WRITE, MAP_SHARED ,fd,offset);
- if(base == MAP_FAILED)
- {
- perror("mmap");
- shm_unlink(name);
- return NULL;
- }
- p_fd = malloc(sizeof(MMAP_FD));
- p_fd->len = len;
- p_fd->name = strdup(name);
- p_fd->fd = fd;
- p_fd->base = base;
- p_fd->offset = offset;
- return p_fd;
- }
- int shm_destroy(MMAP_FD * p_fd)
- {
- if(p_fd == NULL)
- return -1;
- //取消映射
- if(munmap(p_fd->base,p_fd->len) == -1)
- {
- perror("munmap");
- return -1;
- }
- //删除共享内存
- if(shm_unlink(p_fd->name) == -1)
- {
- perror("shm_unlink");
- return -2;
- }
- free(p_fd->name);
- free(p_fd);
- return 0;
- }
- #define SHM_NAME "test_mmap"
- MMAP_FD * p_fd = NULL;
- void exit_handler(int sig)
- {
- printf("EXIT HANDLER\n");
- shm_destroy(p_fd);
- exit(0);
- }
- //创建进程,用于写数据
- void write_proc()
- {
- char ary[10];
- char * p ;
- static int count = 1;
- printf("WRITE SHM\n");
- signal(SIGINT,exit_handler);
- signal(SIGTERM,exit_handler);
- p_fd = shm_map(SHM_NAME,100,0);
- if(p_fd == NULL)
- return ;
- p= malloc(10);
- //注意各种变量地址,ary空间是栈,p是堆的,p_fd->base是内存映射地址
- PRINT_INTX(ary);
- PRINT_INTX(MMAP_ADDR(p_fd));
- PRINT_INTX(p);
- free(p);
- while(1)
- {
- snprintf(MMAP_ADDR(p_fd),p_fd->len,"mmap write %d\n",count++);
- sleep(1);
- }
- }
- void read_proc()
- {
- signal(SIGINT,exit_handler);
- signal(SIGTERM,exit_handler);
- printf("READ SHM\n");
- p_fd = shm_map(SHM_NAME,100,0);
- if(p_fd == NULL)
- return ;
- while(1)
- {
- printf(MMAP_ADDR(p_fd));
- sleep(1);
- }
- }
- int main(int argc,char * argv[])
- {
- if((argc>1) && (argv[1][0] == 'r'))
- read_proc();
- else
- write_proc();
- }
本文转自 驿落黄昏 51CTO博客,原文链接:http://blog.51cto.com/yiluohuanghun/1081585
,如需转载请自行联系原作者