C++跨进程指定地址读写数据失效问题技术求助
问题:进程间通过硬编码内存地址交换数据,修改后无法同步更新
你遇到的核心问题是每个Windows进程都拥有独立的虚拟地址空间,你硬编码的speed_address在两个进程中指向的是各自虚拟空间里的内存区域,并不是真正的共享物理内存。所以Program1修改的是自己进程内的内存,Program2读取的是自己进程内同虚拟地址的内存,两者完全不相干,自然看不到更新。
先看你提供的代码:
Program1.cpp
#include <iostream> #include <windows.h> #include "DataExchange.h" using namespace std; int main(int argc, char** argv) { double val2 = 0; double spd = 1; double* ptr2 = (double*)speed_address; cout << "Program1" << endl; while(1){ DXSetvalue (Speed, spd); val2 = DXGetvalue (Speed); cout << "[speed] = " << spd++ << " [获取到的speed值] = " << val2 << " [地址] = " << ptr2 << "\r" ; Sleep(2000); // 2秒 } return 0; }
Program2.cpp
#include <iostream> #include <windows.h> #include "DataExchange.h" using namespace std; int main(int argc, char** argv) { double t = 0; double val = 0; int* ptr = (int*)speed_address; cout << "Program1 Node" <<endl; init(); while(1){ t += 2; val = DXGetvalue (Speed); cout << "(" << t << "秒) " <<"[Speed] = " << val << " [共享内存地址] = " << ptr << "\r"; Sleep(2000); } }
DataExchange.h
#include "stdio.h" // 值ID宏定义 #define Speed 1 // 值的地址定义 //#define speed_address 0x4a8048 //#define speed_address 0x00CFFB3C #define speed_address 0x7ffef8 // 函数声明 void setaddressValue (double* address, double d); double getaddressValue (int name); double* addressID (int name); void DXSetvalue (int name, double d); double DXGetvalue (int name); void init(); // 函数定义 void setaddressValue (double* address, double d){ double* p = (double*)address; *p = d; //printf("p = 0x%x *p = %lf\n", p, *p); } double getaddressValue (int name){ double* pGet = addressID(name); double value = *pGet; //printf("pGet = 0x%x *pGet = %lf\n", pGet, *pGet); return value; } double* addressID (int name){ switch (name){ case 1: return (double*)speed_address; default: //cout << "未设置地址" << endl; printf("未设置地址!!!\n"); } } /*程序数据*/ void DXSetvalue (int name, double d){ setaddressValue(addressID(name), d); } double DXGetvalue (int name){ return getaddressValue (name); } void init(){ double* p = (double*)speed_address; *p = 0.5; }
解决方案:使用Windows共享内存机制
要实现真正的进程间内存共享,必须使用Windows提供的CreateFileMapping和MapViewOfFileAPI,它们会创建一块所有进程都能访问的共享物理内存区域。
下面是修改后的代码实现:
新的DataExchange.h
#include <windows.h> #include <stdio.h> // 值ID宏定义 #define Speed 1 // 共享内存相关常量 #define SHARED_MEM_NAME L"Global\\MySpeedSharedMem" #define SHARED_MEM_SIZE sizeof(double) // 共享内存指针 static double* g_sharedSpeed = nullptr; // 函数声明 void DXSetvalue(int name, double d); double DXGetvalue(int name); bool initSharedMemory(); void cleanupSharedMemory();
DataExchange.cpp(新增实现文件)
#include "DataExchange.h" bool initSharedMemory() { // 创建或打开共享内存文件映射 HANDLE hMapFile = CreateFileMapping( INVALID_HANDLE_VALUE, // 使用分页文件 NULL, // 默认安全属性 PAGE_READWRITE, // 读写权限 0, // 高32位大小 SHARED_MEM_SIZE, // 低32位大小 SHARED_MEM_NAME); // 共享内存名称 if (hMapFile == NULL) { printf("CreateFileMapping failed: %d\n", GetLastError()); return false; } // 将共享内存映射到当前进程的虚拟地址空间 g_sharedSpeed = (double*)MapViewOfFile( hMapFile, // 文件映射句柄 FILE_MAP_ALL_ACCESS, // 读写访问 0, 0, SHARED_MEM_SIZE); if (g_sharedSpeed == nullptr) { printf("MapViewOfFile failed: %d\n", GetLastError()); CloseHandle(hMapFile); return false; } // 初始化值(只有第一个创建共享内存的进程需要初始化) if (GetLastError() != ERROR_ALREADY_EXISTS) { *g_sharedSpeed = 0.5; } // 可以关闭文件映射句柄,映射的内存依然有效 CloseHandle(hMapFile); return true; } void cleanupSharedMemory() { if (g_sharedSpeed != nullptr) { UnmapViewOfFile(g_sharedSpeed); g_sharedSpeed = nullptr; } } void DXSetvalue(int name, double d) { if (g_sharedSpeed == nullptr) { printf("Shared memory not initialized!\n"); return; } switch (name) { case Speed: *g_sharedSpeed = d; break; default: printf("未设置地址!!!\n"); } } double DXGetvalue(int name) { if (g_sharedSpeed == nullptr) { printf("Shared memory not initialized!\n"); return 0.0; } switch (name) { case Speed: return *g_sharedSpeed; default: printf("未设置地址!!!\n"); return 0.0; } }
修改后的Program1.cpp
#include <iostream> #include <windows.h> #include "DataExchange.h" using namespace std; int main(int argc, char** argv) { if (!initSharedMemory()) { cout << "初始化共享内存失败" << endl; return 1; } double val2 = 0; double spd = 1; cout << "Program1" << endl; while (1) { DXSetvalue(Speed, spd); val2 = DXGetvalue(Speed); cout << "[speed] = " << spd++ << " [获取到的speed值] = " << val2 << "\r"; Sleep(2000); // 2秒 } cleanupSharedMemory(); return 0; }
修改后的Program2.cpp
#include <iostream> #include <windows.h> #include "DataExchange.h" using namespace std; int main(int argc, char** argv) { if (!initSharedMemory()) { cout << "初始化共享内存失败" << endl; return 1; } double t = 0; double val = 0; cout << "Program2" << endl; while (1) { t += 2; val = DXGetvalue(Speed); cout << "(" << t << "秒) " << "[Speed] = " << val << "\r"; Sleep(2000); } cleanupSharedMemory(); return 0; }
关键说明
- 共享内存名称:使用
Global\\前缀可以让不同会话(比如服务和桌面进程)的进程也能访问,普通进程可以去掉Global\\,直接用L"MySpeedSharedMem"。 - 内存映射:
MapViewOfFile会把共享物理内存映射到当前进程的虚拟地址空间,两个进程的虚拟地址可能不同,但指向的是同一块物理内存,所以修改会同步。 - 错误处理:代码中加入了基本的错误检查,方便排查问题。
- 清理资源:程序退出时调用
UnmapViewOfFile释放映射的虚拟地址空间。
内容的提问来源于stack exchange,提问作者Ting-Wei Chien
相关产品推荐
相关产品推荐

