如何用C语言实现共享内存?进程间数据共享有无比临时文件更优方案?
C语言多应用间数据共享方案优化建议
一、现有临时文件方案的核心问题
你当前基于临时文件的实现存在几个明显缺陷:
- 读写依赖磁盘IO,性能远低于内存操作,哪怕是操作系统缓存的文件,也需要经过文件系统层的额外开销
- 无并发控制:多个客户端同时写入
temp.txt时会出现内容覆盖、文件损坏、读写冲突的问题 - 延迟高、资源浪费:服务端采用100ms轮询的方式读取,数据更新不及时,空轮询也会占用不必要的CPU资源
二、更优方案:Windows平台命名共享内存实现
针对你的研究场景,共享内存是所有IPC方案中性能最高的,完全规避了磁盘IO开销,配合命名互斥量做并发控制,可以完美支持任意数量的客户端接入,适配你当前的Windows编译环境。
实现逻辑说明
- 调用Win32 API
CreateFileMapping创建全局命名的共享内存段,大小根据你需要存储的数据量定义 - 调用
MapViewOfFile将共享内存映射到当前进程的地址空间,直接读写内存地址即可完成数据交换 - 搭配全局命名的
Mutex互斥量,保证同一时间只有一个进程在写共享内存,避免竞态条件 - 可选搭配事件(Event)通知服务端数据更新,不需要轮询,进一步降低延迟和CPU占用
三、修改后的代码示例
1. ipc.h
#ifndef IPC #define IPC // 共享内存、互斥量的全局命名,任意进程都可以通过名称打开 #define SHM_NAME "Global\\MySharedMemory" #define MUTEX_NAME "Global\\MySharedMutex" #define SHM_SIZE 256 // 共享内存大小,可根据需求调整 void write_message(int ID); void read_message(); #endif
2. ipc.c
#include <stdlib.h> #include <stdio.h> #include <windows.h> #include "ipc.h" // 共享内存和互斥量的句柄,进程内全局持有 static HANDLE hMapFile = NULL; static HANDLE hMutex = NULL; static LPCTSTR pBuf = NULL; // 初始化共享内存和互斥量,每个进程调用一次 static int init_ipc() { if (hMapFile != NULL && pBuf != NULL && hMutex != NULL) { return 0; } // 创建/打开互斥量 hMutex = CreateMutex(NULL, FALSE, MUTEX_NAME); if (hMutex == NULL) { printf("CreateMutex error: %d\n", GetLastError()); return -1; } // 创建/打开共享内存 hMapFile = CreateFileMapping( INVALID_HANDLE_VALUE, // 用系统页文件做 backing,不需要物理磁盘文件 NULL, // 默认安全属性 PAGE_READWRITE, // 读写权限 0, // 高位大小 SHM_SIZE, // 低位大小 SHM_NAME); // 全局命名 if (hMapFile == NULL) { printf("CreateFileMapping error: %d\n", GetLastError()); CloseHandle(hMutex); hMutex = NULL; return -1; } // 映射到进程地址空间 pBuf = (LPTSTR)MapViewOfFile( hMapFile, // 共享内存句柄 FILE_MAP_ALL_ACCESS, // 读写权限 0, 0, SHM_SIZE); if (pBuf == NULL) { printf("MapViewOfFile error: %d\n", GetLastError()); CloseHandle(hMapFile); CloseHandle(hMutex); hMapFile = NULL; hMutex = NULL; return -1; } return 0; } void write_message(int ID) { if (init_ipc() != 0) { exit(1); } // 加锁,保证独占写入 WaitForSingleObject(hMutex, INFINITE); // 直接写共享内存,和写普通内存操作完全一致 sprintf((char*)pBuf, "ID\t:\t%d\n", ID); // 释放锁 ReleaseMutex(hMutex); } void read_message() { if (init_ipc() != 0) { exit(1); } // 读操作可以不加锁,或者加共享锁,这里简单处理直接读 printf("%s", (char*)pBuf); }
3. client.c 无需修改,和原代码逻辑一致
#include <stdlib.h> #include <stdio.h> #include "ipc.h" int main() { int ID; while(1){ printf("Please enter ID: "); scanf("%d", &ID); write_message(ID); } return 0; }
4. server.c 可保留原轮询逻辑,也可后续加事件通知优化
#include <stdlib.h> #include <stdio.h> #include <windows.h> #include "ipc.h" int main() { while(1){ read_message(); Sleep(100); } return 0; }
四、可扩展优化点
- 去掉轮询逻辑:新增一个全局命名的Event对象,客户端写完数据后调用
SetEvent通知服务端,服务端用WaitForSingleObject等待事件触发,不需要空转Sleep,延迟可以降到微秒级 - 支持多数据缓存:如果需要保存多条客户端写入的记录,可以把共享内存改成环形队列结构,避免旧数据被直接覆盖
- 跨平台适配:如果需要兼容Linux,可以换成POSIX共享内存接口
shm_open+mmap,配合POSIX互斥量实现逻辑完全一致
内容的提问来源于stack exchange,提问作者Louis
相关产品推荐
相关产品推荐

