翼度科技»论坛 云主机 LINUX 查看内容

Linux进程通信 | 共享内存

7

主题

7

帖子

21

积分

新手上路

Rank: 1

积分
21
一、共享内存是什么

在Linux系统中,共享内存是一种IPC(进程间通信)方式,它可以让多个进程在物理内存中共享一段内存区域。
这种共享内存区域被映射到多个进程的虚拟地址空间中,使得多个进程可以直接访问同一段物理内存区域中的数据,从而实现进程间的高速数据交换和通信。
二、共享内存的原理

共享内存基于内核的支持。在共享内存中,内核维护了一块物理内存区域,并将其映射到多个进程的虚拟地址空间中。每个进程都可以使用指针来访问共享内存区域中的数据,就像它们访问自己的内存一样。
三、共享内存的使用方法

相关函数介绍

shmget函数
  1. int shmget(key_t key, size_t size, int shmflg);
复制代码
用于创建或打开一个共享内存区段,具体参数如下:
参数类型说明keykey_t共享内存区段的关键字,用于在多个进程间标识同一个共享内存区段。sizesize_t共享内存区段的大小,以字节为单位。shmflgint共享内存区段的访问权限和行为属性。函数返回值为共享内存区段的标识符 shmid,用于标识已创建或已打开的共享内存区段。
shmat函数
  1. void *shmat(int shmid, const void *shmaddr, int shmflg);
复制代码
用于将共享内存区段连接到当前进程的地址空间,具体参数如下:
参数类型说明shmidint共享内存区段的标识符,用于标识已创建或已打开的共享内存区段。shmaddrconst void*共享内存区段连接到当前进程地址空间的起始地址,如果为 NULL,则由系统自动选择一个地址。shmflgint标志参数,指定共享内存区段的访问权限和行为属性。函数返回值为共享内存区段连接到当前进程地址空间的起始地址,即指向共享内存区段的指针。
shmdt函数
  1. int shmdt(const void *shmaddr);
复制代码
用于断开进程与共享内存区段的连接,具体参数如下:
参数类型说明shmaddrconst void*共享内存区段连接到当前进程地址空间的起始地址。函数返回值为 0 表示成功,-1 表示失败。
shmctl函数
  1. int shmctl(int shmid, int cmd, struct shmid_ds *buf);
复制代码
用于控制共享内存区段的行为,如删除、获取、设置共享内存区段的属性等,具体参数如下:
参数类型说明shmidint共享内存区段的标识符,用于标识已创建或已打开的共享内存区段。cmdint控制命令,指定对共享内存区段的操作类型。bufstruct shmid_ds*指向共享内存区段属性结构体的指针,用于获取或设置共享内存区段的属性。常用的cmd参数包括:

  • IPC_STAT:获取共享内存的状态信息,并将该信息存储在buf参数指向的结构体中。
  • IPC_SET:设置共享内存的状态信息,buf参数指向要设置的新值。
  • IPC_RMID:删除共享内存。
函数返回值为操作成功返回 0,失败返回 -1。
实例演示

以下是一个示例代码,其中一个程序用于写入共享内存,另一个程序用于读取共享内存。
写入程序
  1. /* write.c */
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <unistd.h>
  5. #include <sys/shm.h>
  6. #include <string.h>
  7. #define SHM_SIZE 1024
  8. int main()
  9. {
  10.     int shmid;
  11.     char *shmaddr;
  12.     char write_buf[SHM_SIZE];
  13.     // 创建共享内存段
  14.     shmid = shmget((key_t)1234, SHM_SIZE, 0666|IPC_CREAT);
  15.     if (shmid == -1) {
  16.         perror("shmget failed");
  17.         exit(EXIT_FAILURE);
  18.     }
  19.     // 将共享内存段连接到当前进程
  20.     shmaddr = (char*)shmat(shmid, 0, 0);
  21.     if (shmaddr == (void*)-1) {
  22.         perror("shmat failed");
  23.         exit(EXIT_FAILURE);
  24.     }
  25.     // 从标准输入读取数据并将其写入共享内存
  26.     while(1) {
  27.         fgets(write_buf, SHM_SIZE, stdin);
  28.         strncpy(shmaddr, write_buf, SHM_SIZE);
  29.         if (strncmp(write_buf, "exit", 4) == 0) {
  30.             break;
  31.         }
  32.     }
  33.     // 断开共享内存连接
  34.     if (shmdt(shmaddr) == -1) {
  35.         perror("shmdt failed");
  36.         exit(EXIT_FAILURE);
  37.     }
  38.     // 删除共享内存段
  39.     if (shmctl(shmid, IPC_RMID, 0) == -1) {
  40.         perror("shmctl failed");
  41.         exit(EXIT_FAILURE);
  42.     }
  43.    
  44.     printf("write exit\n");
  45.     return 0;
  46. }
复制代码
读取程序
  1. /* read.c */
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <unistd.h>
  5. #include <sys/shm.h>
  6. #include <string.h>
  7. #define SHM_SIZE 1024
  8. int main()
  9. {
  10.     int shmid;
  11.     char *shmaddr;
  12.     char read_buf[SHM_SIZE];
  13.     // 获取共享内存段
  14.     shmid = shmget((key_t)1234, SHM_SIZE, 0666|IPC_CREAT);
  15.     if (shmid == -1) {
  16.         perror("shmget failed");
  17.         exit(EXIT_FAILURE);
  18.     }
  19.     // 将共享内存段连接到当前进程
  20.     shmaddr = (char*)shmat(shmid, 0, 0);
  21.     if (shmaddr == (void*)-1) {
  22.         perror("shmat failed");
  23.         exit(EXIT_FAILURE);
  24.     }
  25.     // 从共享内存读取数据并输出到标准输出
  26.     while(1) {
  27.         strncpy(read_buf, shmaddr, SHM_SIZE);
  28.         printf("Received message: %s\n", read_buf);
  29.         if (strncmp(read_buf, "exit", 4) == 0) {
  30.             printf("Received exit\n");
  31.             break;
  32.         }
  33.         sleep(1);
  34.     }
  35.     // 断开共享内存连接
  36.     if (shmdt(shmaddr) == -1) {
  37.         perror("shmdt failed");
  38.         exit(EXIT_FAILURE);
  39.     }
  40.     printf("read exit\n");
  41.    
  42.     return 0;
  43. }
复制代码

  • 编译这两个程序
  1. gcc -o write write.c
  2. gcc -o read read.c
复制代码
在一个终端窗口中运行write, 输入消息,在另一个终端窗口中运行read,查看消息。
要退出程序,则在运行write的终端窗口中键入"exit",效果如下:

四、 共享内存的注意事项


  • 使用共享内存需要注意以下几点:

  • 同步问题:由于多个进程可以同时访问共享内存,因此必须要使用同步机制来保证数据的一致性和正确性。
  • 内存泄漏:如果一个进程崩溃或者没有及时解除共享内存映射,就有可能导致内存泄漏的问题。
  • 安全问题:共享内存是多个进程共享的,因此必须要注意数据的安全性和隐私性,避免敏感数据泄露。
五、 共享内存的使用技巧


  • 以下是一些共享内存的使用技巧:

  • 分配内存时使用 shmget() 系统调用中的 IPC_PRIVATE 标记,可以确保共享内存的键值在系统中是唯一的,避免冲突和安全问题。
  • 在读写共享内存之前,使用信号量或互斥锁等同步机制来保证数据的一致性和正确性。
  • 在使用共享内存时,可以将共享内存区域按照固定大小进行分块,避免多个进程同时访问同一块内存区域的冲突。
小结

共享内存是一种高效、灵活、方便的进程间通信方式,可以用于在多个进程之间共享大量数据。
使用共享内存需要注意同步、安全和内存泄漏等问题,可以使用信号量、互斥锁等同步机制来保证数据的正确性。
以上,如果觉得对你有帮助,点个赞再走吧,这样@知微之见也有更新下去的动力!
也欢迎私信我,一起交流!

来源:https://www.cnblogs.com/Wayne123/p/17229686.html
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x

举报 回复 使用道具