03 | linux下进程通信(共享内存)
接下来我们介绍一种简单而高效的进程间通信的方式!
共享内存
注意了是通信也就是数据交换,如果要想避免同时读写发生的同步问题就得需要其他机制!
在实际编程中,常用的同步机制有 信号量、传递消息(使用管道或IPC消息)、生成信号。
但是在这次的实现里面我们用自己提供的非常丑陋的同步标志written_by_you,它是一个非常缺乏效率的忙等待(不停地循环)。
头文件
首先是头文件
//shm_com.h #define TEXT_SZ 2048 struct shared_use_st { int written_by_you; //用来通知消费者 char some_text[TEXT_SZ]; //需要传输的文本长度为2K是由我们随意决定的 };
消费者文件
#include <unistd.h> #include <stdlib.h> #include <stdio.h> #include <string.h> #include <sys/shm.h> //相关的主要函数 #include "shm_com.h" int main() { int running = 1; void *shared_memory = (void*)0; //指向整个共享内存的起点 struct shared_use_st *shared_stuff; //具体的一条消息即结构体 int shmid; //共享内存标识符,不同的进程通过shmget返回的不同,但是shmget的第一个参数都是相同的! srand((unsigned int)getpid()); shmid = shmget((key_t)1234, sizeof(struct shared_use_st), 0666 | IPC_CREAT); //指定 键 、 共享内存大小 、 权限和创建策略 if (shmid == -1) { fprintf(stderr, "shmget failed\n"); exit(EXIT_FAILURE); } //消费者访问内存 (即将共享内存的地址映射到自己进程) //**第二个参数指定的是共享内存连接到当前进程中的地址位置,它通常是一个空指针,表示让系统来选择共享内存出现的地址。** //第三个参数是一组标志。它的两个的可能取值为SHM_RND(这个标志与第二个参数联合使用用来控制共享内存连接的地址)和SHM_RDONLY(它使得连接的 内存只读)。 shared_memory = shmat(shmid, (void*)0, 0); if (shared_memory == (void*)-1) { fprintf(stderr, "shmat failed\n"); exit(EXIT_FAILURE); } printf("memory attached at %X\n", (int)shared_memory); //程序的下一部分将shared_memory分配给shared_stuff,然后它输出written_by_you中的文本 //循环将一支执行到在written_by_you中找到end字符为止。 //sleep调用强迫消费者程序在临界区多呆一会,让生产者程序等待 shared_stuff = (struct shared_use_st*)shared_memory; shared_stuff->written_by_you = 0; while (running) { if (shared_stuff->written_by_you) { printf("you wrote %s", shared_stuff->some_text); sleep(rand() % 4); shared_stuff->written_by_you = 0; if (strncmp(shared_stuff->some_text, "end", 3) == 0) { running = 0; } } } //shmdt函数 将共享内存分离,是shmat的反向操作 if (shmdt(shared_memory) == -1) { fprintf(stderr, "shmdt failed\n"); exit(EXIT_FAILURE); } /*小课堂shmid_ds结构体*/ /* struct shmid_ds{ uid_t shm_perm.uid; uid_t shm_perm.gid; mode_t shm_perm.mode; } */ //shmctl 共享内存的控制函数。 //第一个参数为 标识符 //第二个参数 为 命令:IPC_STAT(将shmid_ds结构中的数据设置为共享内的当前关联值)、IPC_SET(如果当前进程有足够的权限,就把共享内存的关联值设置为shmid_ds结构中给出的值)、IPC_RMID(删除共享内存段) if (shmctl(shmid, IPC_RMID, 0) == -1) { fprintf(stderr, "shmctl(IPC_RMID) failed\n"); exit(EXIT_FAILURE); } exit(EXIT_SUCCESS); }
生产者文件
#include <unistd.h> #include <stdlib.h> #include <stdio.h> #include <string.h> #include <sys/shm.h> #include "shm_com.h" int main() { int running = 1; void *shared_memory = (void*)0; struct shared_use_st *shared_stuff; char buffer[BUFSIZ]; int shmid; shmid = shmget((key_t)1234, sizeof(struct shared_use_st), 0666 | IPC_CREAT); if (shmid == -1) { fprintf(stderr, "shmget failed\n"); exit(EXIT_FAILURE); } //生产者访问共享内存 shared_memory = shmat(shmid, (void*)0, 0); if (shared_memory == (void*)-1) { fprintf(stderr, "shmat failed\n"); exit(EXIT_FAILURE); } printf("memory attached at %X\n", (int)shared_memory); shared_stuff = (struct shared_use_st*)shared_memory; while (running) { while (shared_stuff->written_by_you == 1) { sleep(1); printf("waiting for client...\n"); } printf("enter some text: "); fgets(buffer, BUFSIZ, stdin); strncpy(shared_stuff->some_text, buffer, TEXT_SZ); shared_stuff->written_by_you = 1; if (strncmp(buffer, "end", 3) == 0) { running = 0; } } //分离共享内存 if (shmdt(shared_memory) == -1) { fprintf(stderr, "shmdt failed\n"); exit(EXIT_FAILURE); } exit(EXIT_SUCCESS); }
效果展示
尽管使用的是同一块物理地址,在各个进程中的地址也不同 啊!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)