Windows 共享内存和不同的编译器奇怪的行为
Posted
技术标签:
【中文标题】Windows 共享内存和不同的编译器奇怪的行为【英文标题】:Windows Shared memory and different Compilers weird behavior 【发布时间】:2014-08-06 17:04:02 【问题描述】:我让两个不同的进程使用共享内存相互交互,我观察到由于某种原因它不能按预期工作,问题是,当我放入数据时,缓冲区由于某种原因被额外的零填满进去。这是我的工作:
Process1 vc++(msvc2012主动解决平台Win32):
LPTSTR pBuf =(LPTSTR) MapViewOfFile(hMap, // handle to map object
FILE_MAP_ALL_ACCESS, // read/write permission
0,
0,
256);
if(!pBuf)
//handle errors
WaitForSingleObject(hExchangeData,INFINITE); //here i'm waiting data from the second process it should be DWORD value
DWORD someValue=0;
CopyMemory((PVOID)&someValue,pMemBuf,sizeof(DWORD)); //i get it and everything is ok, then the second process waits for this process to put some data in
int pBufSize=sizeof(DWORD); //counter
CopyMemory((PVOID)(pBuf+pBufSize),&hHandle1,sizeof(HANDLE));
pBufSize+=sizeof(HANDLE);
CopyMemory((PVOID)(pBuf+pBufSize),&hHandle1,sizeof(HANDLE));
SetEvent(exDone);
这里是流程二,用MinGW写的:线程模型:win32,gcc version 4.8.1 (GCC)
pBuf = (LPTSTR) MapViewOfFile(hMap,
FILE_MAP_WRITE | FILE_MAP_READ,
0,
0,
256);
if (pBuf == NULL)
//handle errors
DWORD myVal = 228;
memcpy(pBuf,&myVal,sizeof(DWORD)); //here i wrote some dword in there which first process is successfully receiving
SetEvent(dwordWritten);
int mySize = sizeof(DWORD); // counter
WaitForSingleObject(handlesWrittine,INFINITE); //waiting for some handles
CopyMemory((PVOID)&myHandle1,(PVOID)(pBuf+mySize),sizeof(HANDLE));
mySize += sizeof(HANDLE);
CopyMemory((PVOID)&myHandle2,(PVOID)(pBuf+mySize),sizeof(HANDLE));
所以基本上在第一个进程(msvc)中,我写了两个长度为 4 字节的句柄,因为在两个版本上 sizeof(HANDLE) =4
,我检查了 printf
,并且我希望在第二个中也收到 4 个字节(mingw+gcc) 进程,但是发生的是第一个进程中的内存缓冲区结构看起来像这样
1234 //dword
0012 //handle1
0013 //handle2
但在第二个过程中:
1234 //dword
0000
0012 //handle1
0000
0013 //handle3
所以从第二个进程最后一个CopyMemory
指令我得到0012 句柄值。为什么会有这样的不同?为什么我在第二个过程中得到额外的零?我尝试将 msvc 平台用于两个进程,它工作正常,但使用 mingw,gcc 没有。
【问题讨论】:
听起来像是成员变量的对齐和填充问题。 @CaptainObvlious 我需要将这三个变量对齐到零对齐? pBuf 被声明为 LPTSTR 是问题所在。请参阅我的新答案。 【参考方案1】:这次我看到了真正的问题。
pBuf 是 LPTSTR 类型。在 UNICODE 上构建的是一个短*指针。在 ANSI 构建中,这是一个 char* 指针。我怀疑您的 Visual Studio 项目在构建环境中定义了 UNICODE,而 MinGW 没有。因此,第一个代码示例中 CopyMemory 调用中的这个表达式:
(pBuf+mySize)
计算 pBuf 增加 mySize*2 个字节。
简单的解决方法是将 pBuf 声明为 LPSTR 类型或 char*。
char* pBuf = (char*) MapViewOfFile(hMap, // handle to map object
FILE_MAP_ALL_ACCESS, // read/write permission
0,
0,
256);
应该可以的。
【讨论】:
谢谢,成功了!我对窗户类型的疏忽让我浪费了很多时间。【参考方案2】:几个问题。
首先,这条线看起来很离谱:
mySize += HANDLE;
这甚至可以编译吗?你不打算说mySize += sizeof(HANDLE)
无论如何,你确定 sizeof(HANDLE)
在 MinGW 中是 4 吗?我有疑问。
HANDLE 通常在<winnt.h>
中定义如下
typedef void *HANDLE;
所以sizeof(HANDLE)
将是 4 或 8,具体取决于您是构建为 32 位还是 64 位版本。
我怀疑您的 Visual Studio 配置处于 32 位模式,因为这是通常的默认设置。你的 MinGW 版本是 64 位的。
如果您将 Visual Studio 项目配置为生成 64 位版本,您将看到相同的差异。
【讨论】:
对不起,我正在编辑帖子并把代码弄乱了一点,是的,它是mySize += sizeof(HANDLE)
,我使用printf("sizeof(HANDLE)=%d\n",sizeof(HANDLE));
检查了它等于4,另外我从控制台仔细检查了它带有print
的gdb调试器。
在任务管理器中我的进程也显示为process.exe*32
以上是关于Windows 共享内存和不同的编译器奇怪的行为的主要内容,如果未能解决你的问题,请参考以下文章