Linux编程基础之进程间通信之四:共享内存

- 日理万妓 2022-06-16 09:37 79阅读 0赞

一、共享内存的概述

共享内存是一种最为高效的进程间通信方式。因为进程可以直接读写内存,不需要任何数据的复制。为了在多个进程间交换信息,内核专门留出了一块内存区。这段内存区可以由需要访问的进程将其映射到自己的私有地址空间。因此,进程就可以直接读写这一内存区而不需要进行数据的复制,从而大大提高了效率。其原理基本示意图如下所示:

Center

二、共享内存的一般使用方法和基本原理

1、一般使用方法

共享内存的实现分为两个步骤,第一步是创建共享内存,这里用到的函数是shmget(),也就是从内存中获得一段共享内存区域,第二步映射共享内存,也就是把这段创建的共享内存映射到具体的进程空间中,这里使用的函数是shmat()。到这里,就可以使用这段共享内存了,也就是可以使用不带缓冲的I/O 读写命令对其进行操作。除此之外,当然还有撤销映射的操作,其函数为shmdt()。在共享内存使用完毕之后调用shmctl()函数将创建的共享内存销毁。

2、主要函数

a、创建或者获得一个共享内存

  1. int shmget(key_t key, int size, int shmflg)
  2. key 共享内存的键值,多个进程可以通过它访问同一个共享内存,其中有个特殊值IPC\_PRIVATE。它用于创建当前进程的私有共享内存
  3. size 共享内存区大小
  4. shmflg open()函数的权限位,也可以用八进制表示法
  5. 返回值:成功返回共享内存段标识符,失败返回-1

b、映射共享内存

  1. char *shmat(int shmid, const void *shmaddr, int shmflg)
  2. shmid 要映射的共享内存区标识符
  3. shmaddr 将共享内存映射到指定地址(若为0 则表示系统自动分配地址并把该段共享内存映射到调用进程的地址空间)
  4. shmflg SHM\_RDONLY:共享内存只读;默认0:共享内存可读写
  5. 返回值:成功返回被映射的段地址,失败返回-1

c、撤销映射共享内存

  1. int shmdt(const void *shmaddr)
  2. shmaddr 被映射的共享内存段地址
  3. 返回值:成功返回0,失败返回-1

d、共享内存控制函数

  1. int shmctl(int shmid, int cmd, struct shmid_ds *buf);
  2. shmid :要映射的共享内存区标识符
  3. cmd 控制共享内存的命令,比如IPC\_RMID,销毁一个共享内存
  4. buf argument is a pointer to a shmid\_ds structure
  5. 返回值:返回0成功,返回-1失败

三、测试

编写一个测试共享内存的例子:

shmem_write.c : 定义一块共享内存,向共享内存中写入一个消息

shmem_read.c : 将共享内存中的消息打印出来

shmem_write.c的具体实现如下:

  1. #include <unistd.h>
  2. #include <stdio.h>
  3. #include <sys/types.h>
  4. #include <sys/ipc.h>
  5. #include <sys/shm.h>
  6. #include <string.h>
  7. #include <sys/types.h>
  8. #include <sys/wait.h>
  9. #include <stdlib.h>
  10. /* 定义共享内存的大小 */
  11. #define SHMEM_SIZE 256
  12. /* 向共享内存中写入一个消息,消息由用户传入
  13. * usage : shmem_write <msg>
  14. */
  15. int main(int argc, char *argv[])
  16. {
  17. key_t key;
  18. int shmid;
  19. char *buffer;
  20. if(2 != argc)
  21. {
  22. printf("usage : %s <msg>\n", argv[0]);
  23. return -1;
  24. }
  25. /* 构造一个共享内存的键值 */
  26. key = ftok("key_file", 0x3);
  27. if(-1 == key)
  28. {
  29. printf("ftok error!\n");
  30. return -1;
  31. }
  32. /* 创建一块共享内存 */
  33. shmid = shmget(key, SHMEM_SIZE, IPC_CREAT | 0666);
  34. if(-1 == shmid)
  35. {
  36. printf("shmget error!\n");
  37. return -1;
  38. }
  39. /* 将共享内存映射到当前进程空间 */
  40. buffer = (unsigned char*)shmat(shmid, 0, 0);
  41. if(buffer == (void *)-1)
  42. {
  43. printf("shmat error!\n");
  44. return -1;
  45. }
  46. /* 将传入的内如写入到共享内存当中 */
  47. strncpy(buffer, argv[1], strlen(argv[1]));
  48. /* 撤销共享内存在当前进程的映射 */
  49. shmdt(buffer);
  50. return 0;
  51. }

shmem_read.c的具体实现如下:

  1. #include <unistd.h>
  2. #include <stdio.h>
  3. #include <sys/types.h>
  4. #include <sys/ipc.h>
  5. #include <sys/shm.h>
  6. #include <string.h>
  7. #include <sys/types.h>
  8. #include <sys/wait.h>
  9. #include <stdlib.h>
  10. /* 定义共享内存的大小 */
  11. #define SHMEM_SIZE 256
  12. /* 读出共享内存当中的内容
  13. *
  14. */
  15. int main(void)
  16. {
  17. key_t key;
  18. int shmid;
  19. int ret;
  20. char *buffer;
  21. /* 构造访问共享内存的键值 */
  22. key = ftok("key_file", 0x03);
  23. if(-1 == key)
  24. {
  25. printf("ftok error!\n");
  26. return -1;
  27. }
  28. /* 创建一块共享内存 */
  29. shmid = shmget(key, SHMEM_SIZE, IPC_CREAT | 0666);
  30. if(-1 == shmid)
  31. {
  32. printf("shmget error!\n");
  33. return -1;
  34. }
  35. /* 将共享内存映射到当前进程空间 */
  36. buffer = (unsigned char*)shmat(shmid, 0, 0);
  37. if(buffer == (void *)-1)
  38. {
  39. printf("shmat error!\n");
  40. return -1;
  41. }
  42. /* 将共享内存中的内容读取出来 */
  43. printf("The msg is %s\n", buffer);
  44. /* 撤销共享内存在当前进程的映射 */
  45. shmdt(buffer);
  46. /* 删除这块共享内存 */
  47. ret = shmctl(shmid, IPC_RMID, NULL);
  48. if(-1 == ret)
  49. {
  50. printf("shmctl error!\n");
  51. return -1;
  52. }
  53. return 0;
  54. }

编译并运行结果如下所示:

Center 1

发表评论

表情:
评论列表 (有 0 条评论,79人围观)

还没有评论,来说两句吧...

相关阅读

    相关 Linux进程通信共享

    共享内存的实现:两个不同进程共享同一块物理内存,达到访问同一份资源的目的 ![这里写图片描述][SouthEast] 共享内存是所有进程间通信速度最快的一种方式,省去了数

    相关 进程通信共享

    进程间通信之共享内存 共享内存就是不同进程之间共享的一块内存区域。一般情况下,每个进程都有自己独立的内存空间,一个进程不能直接访问其他进程的内存区域,这样就使得进程与进程之间