Linux下基于POSIX标准的共享内存操作示例

来源:互联网 发布:淘宝助理不能上传 编辑:程序博客网 时间:2024/06/17 23:22

   对于进程间通信,之前一直是用管道进行实现。比如父子进程间使用pipe,无血缘关系的进程可以使用fifo。从来没有想过使用共享内存,为什么呢?大家还记得这本书吧《Unix环境高级编程》,上面讲解了关于共享内存的操作,说实话,太麻烦了,真的不好用(有好多繁杂的接口,比如shmget, shmat,shmdt,chmctl等)。现在好了,基于POSIX标准的共享内存操作变得及其简单,总共就几个接口可供调用,已经变得像操作普通文件一样简单!

        新的标准的接口如下:

        POSIX 为创建、映射、同步和取消共享内存段提供五个入口点:

  • shm_open():创建共享内存段或连接到现有的已命名内存段。这个系统调用返回一个文件描述符。
  • shm_unlink():根据(shm_open() 返回的)文件描述符,删除共享内存段。实际上,这个内存段直到访问它的所有进程都退出时才会删除,这与在 UNIX 中删除文件很相似。但是,调用 shm_unlink() (通常由原来创建共享内存段的进程调用)之后,其他进程就无法访问这个内存段了。
  • mmap():把共享内存段映射到进程的内存。这个系统调用需要 shm_open() 返回的文件描述符,它返回指向内存的指针。(在某些情况下,还可以把一般文件或另一个设备的文件描述符映射到内存。对这些操作的讨论超出了本文的范围;具体方法请查阅操作系统的 mmap() 文档。)
  • munmap():作用与 mmap() 相反。
  • msync():用来让共享内存段与文件系统同步 — 当把文件映射到内存时,这种技术有用。

使用共享内存的过程是,用 shm_open() 创建内存段,用 write() 或 ftruncate() 设置它的大小,用 mmap() 把它映射到进程内存,执行其他参与者需要的操作。当使用完时,原来的进程调用 munmap() 和 shm_unlink(),然后退出。

      怎么样?简单吧,就像文件操作一样,打开,映射得到一个指针,对指针操作,然后撤销映射,关闭!

      下面给出两段示例代码,以示用来进行无血缘关系的进程间通信

[cpp] view plaincopy
  1.    #include <sys/file.h>  
  2.  6 #include <sys/mman.h>  
  3.  7 #include <fcntl.h>  
  4.  8 #include <sys/stat.h>  
  5.  9 #include <sys/wait.h>  
  6. 10 #include "util.h"  
  7. 11   
  8. 12 void error_and_die(const char *msg) {  
  9. 13     perror(msg);  
  10. 14     exit(EXIT_FAILURE);  
  11. 15 }  
  12. 16   
  13. 17 int main()  
  14. 18 {  
  15. 19     int ret;  
  16. 20     const size_t region_size = sysconf(_SC_PAGE_SIZE);  
  17. 21     const char *string = "This is a test for share memory!/n";  
  18. 22     int fd = shm_open(SHARE_MEMORY, O_CREAT | O_TRUNC | O_RDWR, 0666);  
  19. 23     if (-1 == fd)  
  20. 24     {  
  21. 25         error_and_die("shm_open");  
  22. 26     }  
  23. 27   
  24. 28     ret = ftruncate(fd, region_size);  
  25. 29     if (ret)  
  26. 30     {  
  27. 31         error_and_die("ftruncate");  
  28. 32     }  
  29. 33   
  30. 34     void *ptr = mmap(0, region_size, PROT_READ | PROT_WRITE , MAP_SHARED, fd, 0);  
  31. 35     if (ptr == MAP_FAILED)  
  32. 36     {  
  33. 37         error_and_die("mmap");  
  34. 38     }  
  35. 39   
  36. 40     close(fd);  
  37. 41     //*(int *)ptr = 0x55aa;  
  38. 42     memcpy(ptr, string, (strlen(string) + 1));  
  39. 43   
  40. 44     sleep(10);  
  41. 45   
  42. 46     ret = munmap(ptr, region_size);  
  43. 47     if (ret)  
  44. 48         error_and_die("munmap");  
  45. 49   
  46. 50     ret = shm_unlink(SHARE_MEMORY);  
  47. 51     if (ret)  
  48. 52         error_and_die("shm_unlink");  
  49. 53     return 0;  
  50. 54   
  51. 55   
  52. 56 }  

[cpp:nogutter] view plaincopy
  1. 1 #include <stdio.h>  
  2.   2 #include <string.h>  
  3.   3 #include <stdlib.h>  
  4.   4 #include <unistd.h>  
  5.   5 #include <sys/file.h>  
  6.   6 #include <sys/mman.h>  
  7.   7 #include <fcntl.h>  
  8.   8 #include <sys/stat.h>  
  9.   9 #include <sys/wait.h>  
  10.  10 #include "util.h"  
  11.  11   
  12.  12 void error_and_die(const char *msg) {  
  13.  13     perror(msg);  
  14.  14     exit(EXIT_FAILURE);  
  15.  15 }  
  16.  16   
  17.  17 int main()  
  18.  18 {  
  19.  19     int ret;  
  20.  20     const size_t region_size = sysconf(_SC_PAGE_SIZE);  
  21.  21     int fd = shm_open(SHARE_MEMORY, O_CREAT | O_RDWR, 0666);  
  22.  22     if (-1 == fd)  
  23.  23     {  
  24.  24         error_and_die("shm_open");  
  25.  25     }  
  26.  26   
  27.  27     ret = ftruncate(fd, region_size);  
  28.  28     if (ret)  
  29.  29     {  
  30.  30         error_and_die("ftruncate");  
  31.  31     }  
  32.  32   
  33.  33     void *ptr = mmap(0, region_size, PROT_READ | PROT_WRITE , MAP_SHARED, fd, 0);  
  34.  34     if (ptr == MAP_FAILED)  
  35.  35     {  
  36.  36         error_and_die("mmap");  
  37.  37     }  
  38.  38   
  39.  39     close(fd);  
  40.  40   
  41.  41   
  42.  42     printf("%s", (char *)ptr);  
  43.  43     ret = munmap(ptr, region_size);  
  44.  44     if (ret)  
  45.  45         error_and_die("munmap");  
  46.  46   
  47.  47     ret = shm_unlink(SHARE_MEMORY);  
  48.  48     if (ret)  
  49.  49         error_and_die("shm_unlink");  
  50.  50   
  51.  51     return 0;  
  52.  52 }  

 

代码很简单,唯一注意的地方是,第二个文件中shm_open的时候O_TUNC参数要去掉,否则内存又被截断为0,读不到东西的。

原创粉丝点击