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 共享内存和不同的编译器奇怪的行为的主要内容,如果未能解决你的问题,请参考以下文章

OpenCV 的奇怪行为

QMessageBoxes 在 OSX 中有非常奇怪的行为

VS2012 编译器奇怪的内存释放问题

跨语言共享环境变量

调用fread后奇怪的printf行为

Linux 上 fortran 代码的 Intel Vtune 奇怪行为