C++ Linux共享内存
跳到导航
跳到搜索
概念与原理
共享内存是一种高效的进程间通信机制,允许多个进程直接访问同一块物理内存。共享内存是所有IPC机制中最快的,因为数据不需要在内核和用户空间之间进行复制。
核心点
- 创建共享内存:使用shmget系统调用创建。
- 附加共享内存:使用shmat系统调用将共享内存附加到进程地址空间。
- 分离共享内存:使用shmdt系统调用分离共享内存。
- 删除共享内存:使用shmctl系统调用删除共享内存。
实现实例
#include <iostream> #include <sys/ipc.h> #include <sys/shm.h> #include <sys/wait.h> #include <cstring> #include <unistd.h> #define SHM_SIZE 1024 // 共享内存大小 int main() { key_t key = ftok("shmfile", 65); // 生成唯一键 int shmid = shmget(key, SHM_SIZE, 0666|IPC_CREAT); // 创建共享内存段 char *str = (char*) shmat(shmid, nullptr, 0); // 附加到共享内存 pid_t cpid = fork(); if (cpid == -1) { perror("fork"); exit(EXIT_FAILURE); } if (cpid == 0) { // 子进程 sleep(1); // 确保父进程先写入 std::cout << "子进程从共享内存读取数据:\n"; std::cout << str << std::endl; shmdt(str); // 分离共享内存 _exit(EXIT_SUCCESS); } else { // 父进程 std::cout << "父进程写入共享内存:\n"; const char* msg = "来自父进程的消息"; strncpy(str, msg, SHM_SIZE); wait(NULL); // 等待子进程 shmdt(str); // 分离共享内存 shmctl(shmid, IPC_RMID, nullptr); // 删除共享内存 exit(EXIT_SUCCESS); } }
解析:
ftok("shmfile", 65):生成一个唯一键。
shmget(key, SHM_SIZE, 0666 | IPC_CREAT):创建共享内存段。
shmat(shmid, NULL, 0):将共享内存段附加到进程地址空间。
子进程:等待父进程将数据写入共享内存,从共享内存读取数据并显示。
父进程:将数据写入共享内存,等待子进程结束,分离并删除共享内存段。
运行结果:
父进程写入共享内存: 子进程从共享内存读取数据: 来自父进程的消息
实现实例2
共享内存写入端
#include <iostream> #include<unistd.h>//unix stand lib #include<sys/types.h> #include<sys/fcntl.h> #include<sys/stat.h> #include<stdio.h> #include<fcntl.h> #include<string.h> #include<dirent.h>//file dir #include <sys/wait.h>//wait func #include <stdlib.h>//ststem #include <signal.h> #include <string.h> #include <sys/msg.h> #include <sys/ipc.h> #include <sys/shm.h> using namespace std; typedef struct { int age; char name[10]; }STU; #define SHM_ZIZE_MAX 4096 int main(int argc, char *argv[]) { int shm_id; shm_id = shmget((key_t)6677, SHM_ZIZE_MAX, IPC_CREAT | 0666);//666可读可写 if (shm_id == -1) { perror("shm create error"); return -1; } STU stu_info = { 19, "rabbit" }; void *shm_addr = NULL; //shmat的第二个参数shm_addr:把共享内存连接到当前进程去的时候准备放置它的那个地址,为NULL为让系统自动选择 //第三个参数是一组按位OR(或)在一起的标志,0表示可读可写 shm_addr = shmat(shm_id, NULL, 0); //要对内存清空一下 memset(shm_addr, 0, SHM_ZIZE_MAX); //写进内存:memcpy因为映射就看做是自己的内存 memcpy(shm_addr, &stu_info, sizeof(STU));//地址,内容,大小 cout << "memcpy(shm_addr, &stu_info, sizeof(STU))" << endl; while(1){sleep(1);} shmdt(shm_addr);//脱钩函数 return 0; }
共享内存读出端
#include <iostream> #include<unistd.h>//unix stand lib #include<sys/types.h> #include<sys/fcntl.h> #include<sys/stat.h> #include<stdio.h> #include<fcntl.h> #include<string.h> #include<dirent.h>//file dir #include <sys/wait.h>//wait func #include <stdlib.h>//ststem #include <signal.h> #include <string.h> #include <sys/msg.h> #include <sys/ipc.h> #include <sys/shm.h> typedef struct { int age; char name[10]; }STU; #define SHM_ZIZE_MAX 4096 int main(int argc, char *argv[]) { int shm_id; shm_id = shmget((key_t)6677, SHM_ZIZE_MAX, IPC_CREAT | 0666);//666可读可写 if (shm_id == -1) { perror("shm create error"); return -1; } STU stu_info; STU *recv_stu_info; bzero(&stu_info, sizeof(STU)); void *shm_addr = NULL; //shmat的第二个参数shm_addr:把共享内存连接到当前进程去的时候准备放置它的那个地址,为NULL为让系统自动选择 //第三个参数是一组按位OR(或)在一起的标志,SHM_RDONLY表示只读 shm_addr = shmat(shm_id, NULL, SHM_RDONLY); //法一:从内存中拿出来:memcpy因为映射就看做是自己的内存 //memcpy(&stu_info, shm_addr,sizeof(STU));//地址,内容,大小 //cout << "stu_info.name" << stu_info.name << endl; //法二:也可以直接把共享内存指针强制转换成STU*,这时要shmat的参数3改为0读写 //这里也说明如果有进程把数据写入共享内存,如果没有其他进程去修改或清除 //那么数据永远都在里面,消息队列和共享内存里面的数据生命周期和进程不同(进程消失了数据可以还在) recv_stu_info = (STU*)shm_addr; cout << "stu_info.name" << recv_stu_info->name << endl; shmdt(shm_addr);//脱钩函数 return 0; }