1. 程式人生 > >linux進程間通信之Posix共享內存用法詳解及代碼舉例

linux進程間通信之Posix共享內存用法詳解及代碼舉例

函數 ini 復制代碼 define 進程 a.out IV 使用 init

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. close(fd);
  46. setbuf(stdout,NULL);//stdout is unbuffered
  47. if(0==fork())
  48. {
  49. for(i=0;i<TIMES;i++)
  50. {
  51. #if SEM_IN_SHAREMEMORY
  52. sem_wait(&ptr->mutex);
  53. printf("child : %d\n",ptr->count++);
  54. sem_post(&ptr->mutex);
  55. #else
  56. sem_wait(mutex);
  57. printf("child : %d\n",(*ptr)++);
  58. sem_post(mutex);
  59. #endif
  60. }
  61. exit(0);
  62. }
  63. for(i=0;i<TIMES;i++)
  64. {
  65. #if SEM_IN_SHAREMEMORY
  66. sem_wait(&ptr->mutex);
  67. printf("parent : %d\n",ptr->count++);
  68. sem_post(&ptr->mutex);
  69. #else
  70. sem_wait(mutex);
  71. printf("parent : %d\n",(*ptr)++);
  72. sem_post(mutex);
  73. #endif
  74. }
  75. exit(0);
  76. }
復制代碼

運行結果:

./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不在共享內存區

linux進程間通信之Posix共享內存用法詳解及代碼舉例