linux进程间通信之Posix共享内存用法详解及代码举例

Posix共享内存有两种非亲缘进程间的共享内存方法:
1).  使用内存映射文件,由open函数打开,再由mmap函数把返回的文件描述符映射到当前进程空间中的一个文件。

2). 使用共享内存区对象,由shm_open打开一个 Posix IPC名字。再由mmap把返回的描述符映射到当前进程的地址空间。

Posix共享内存相关函数头文件及原型:
#include <sys/mman.h>
int shm_open(const char *name, int oflag, mode_t mode);
功能:打开一个共享内存对象,获取描述符
返回值:成功返回非负描述符,出错返回-1
参数:name是Posix IPC名字;oflag参数为O_RDONLY或O_RDWR,还可以为O_CREAT,O_EXCL,O_TRUNC,当在共享内存对象已存在的情况下指定O_RDWR和O_TRUNC会被截短为长度0;mode是指定权限位,在有O_CREAT指定的情况下使用,没有O_CREAT时也要必须设为0。


int shm_unlink(const char *name);
功能:删除一个共享内存区对象的名字。
返回值: 成功返回0,出错返回-1.


void *mmap(void *addr, size_t len, int prot, int flags, int fd, off_t offset);
功能:把由shm_open打开的共享内存对象映射到进程地址空间。
返回值:若成功则返回映射区的起始地址,出错返回MAP_FAILED。
参数: addr指定被映射到的进程空间的起始地址,一般设为空指针NULL,表示自动分配;len是映射到地址空间的字节数,从文件头开始第offset个字节开始算,一般offset设置为0;prot可以为PROT_READ(可读),PROT_WRITE(可写),PROT_EXEC(可执行),PROT_NONE(不可访问);flags可以为MAP_SHARED,MAP_PRIVATE,MAP_FIXED,其中MAP_SHARED或MAP_PRIVATE必须指定一个,MAP_FIXED一般不指定并且addr为空指针,表示自动分配地址,方便移植。

int munmap(void  *addr, size_t len);
功能:删除进程地址空间的映射关系
返回值:成功返回0,出错返回-1


int msync(void *addr, size_t len, int flags);
功能:是文件内容与内存映射区中内容一致。
返回值: 成功返回0,出错返回-1.
参数: flags有3种,MS_ASYNC(异步写),MS_SYNC(同步写),MS_INVALIDATE(使缓存的数据失效)。

代码举例shm_test.c,父子进程操作共享内存区变量计数加1,并且用信号量sem做同步

  1. #include <stdlib.h>
  2. #include <stdio.h>
  3. #include <sys/mman.h>
  4. #include <semaphore.h>
  5. #include <fcntl.h>
  6. #define MYFILE "./shm_test_file"
  7. #define SEM_NAME "/mysem"
  8. #define MYSHM "/myshm"
  9. #define TIMES 5
  10. #define USE_SHM_OPEN 0
  11. #define SEM_IN_SHAREMEMORY 0
  12. #if SEM_IN_SHAREMEMORY
  13. struct shared
  14. {
  15.   sem_t mutex;
  16.   int count;
  17. }shared;
  18. #endif
  19. int main(void)
  20. {
  21.   int fd,i,zero=0;
  22.   #if SEM_IN_SHAREMEMORY
  23.   struct shared *ptr;
  24.   #if USE_SHM_OPEN
  25.   fd=shm_open(MYSHM,O_RDWR|O_CREAT,0666);
  26.   #else
  27.   fd=open(MYFILE,O_RDWR|O_CREAT,0666);
  28.   #endif
  29.   write(fd,&shared,sizeof(struct shared));
  30.   ptr=mmap(NULL,sizeof(struct shared),PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
  31.   sem_init(&ptr->mutex,1,1);
  32.   #else
  33.   int *ptr;
  34.   sem_t *mutex;
  35.   #if USE_SHM_OPEN
  36.   fd=shm_open(MYSHM,O_RDWR|O_CREAT,0666);
  37.   #else
  38.   fd=open(MYFILE,O_RDWR|O_CREAT,0666);
  39.   #endif
  40.   write(fd,&zero,sizeof(int));
  41.   ptr=mmap(NULL,sizeof(int),PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
  42.   mutex=sem_open(SEM_NAME,O_CREAT|O_EXCL,0666,1);
  43.   sem_unlink(SEM_NAME);
  44.   #endif
  45.   
  46.   
  47.   close(fd); 
  48.   setbuf(stdout,NULL);//stdout is unbuffered
  49.   if(0==fork())
  50.   {
  51.     for(i=0;i<TIMES;i++)
  52.     {
  53.       #if SEM_IN_SHAREMEMORY
  54.       sem_wait(&ptr->mutex);
  55.       printf("child : %d\n",ptr->count++);
  56.       sem_post(&ptr->mutex);
  57.       #else
  58.       sem_wait(mutex);
  59.       printf("child : %d\n",(*ptr)++);
  60.       sem_post(mutex);
  61.       #endif
  62.     }
  63.     exit(0);
  64.   }
  65.   
  66.   for(i=0;i<TIMES;i++)
  67.   {
  68.       #if SEM_IN_SHAREMEMORY
  69.       sem_wait(&ptr->mutex);
  70.       printf("parent : %d\n",ptr->count++);
  71.       sem_post(&ptr->mutex);
  72.       #else
  73.       sem_wait(mutex);
  74.       printf("parent : %d\n",(*ptr)++);
  75.       sem_post(mutex);
  76.       #endif
  77.   }
  78.   exit(0);
  79. }
复制代码

运行结果:

./a.out
parent : 0
parent : 1
parent : 2
parent : 3
parent : 4
child : 5
child : 6
child : 7
child : 8
child : 9


通过设置“#define USE_SHM_OPEN 1”使用共享内存对象映射,“#define USE_SHM_OPEN 0” 使用不同文件系统映射。
设置“#define SEM_IN_SHAREMEMORY 1”使信号量SEM也放在共享内存区,“#define SEM_IN_SHAREMEMORY 0”使信号量SEM不在共享内存区

猜你喜欢

转载自www.cnblogs.com/wudymand/p/9226526.html