在Windows下使用共享内存实现多进程通信,各进程中对共享内存中地址结构操作后不一致

hoopool 2015-10-03 03:30:12
在一个DLL工程中,利用CreateFileMapping和MapViewOfFile创建一个命名共享内存,应用进程通过加载该DLL工程后创建一个共享内存,并将获取的共享内存给一个结构体,同时将该结构体中的初始化标志位bInit置位,并初始化该结构体。其他进程在创建共享内存后(创建同名共享内存返回已存在的)判断该结构体中的标志位,如果置位,则不再重新初始化。
初始化时会对结构体中的一个链表成员结构(双向循环)进行初始化(形成环)。

问题是:在第一个进程创建完并初始化后,另一个进程可以判断出该结构已被初始化,则不会对其再次进行初始化,但是在单步跟该进程时,看到结构中的链表成员并没有形成环。是不是因为在每个进程中对地址操作都是虚拟地址,因此指针操作并不会真正记录地址?




// ShareMem.dll 创建共享内存的动态库工程
// ShareMem.h

#ifndef __SHAREMEM_H__
#define __SHAREMEM_H__

#include <Windows.h>


#define EXPORT_API_DLL __declspec(dllexport)


typedef struct LIST_HEAD{

LIST_HEAD* Next;
LIST_HEAD* Prev;
}_LIST_HEAD;


typedef struct {

int nSize;
_LIST_HEAD Item;
}_MemoryBlock;


typedef struct {

int nSize;
bool bInit;
_LIST_HEAD FreeBlockList;
}_ShareMemTable;


typedef struct {

HANDLE hShareMemHandle;
_ShareMemTable *lpShareMemTable;
}_ProcessTable;


class ShareMem {

public:
EXPORT_API_DLL ShareMem();
~ShareMem() {}

protected:
unsigned short ShareMemInit();
char* CreatShareMem(unsigned int nSize);
};

#endif __SHAREMEM_H__






// ShareMem.dll 创建共享内存的动态库工程
// ShareMem.cpp

#include "ShareMem.h"

_ProcessTable *s_ProcessTable = {0};

// 开辟共享内存空间
char* ShareMem :: CreatShareMem(unsigned int nSize) {

int nResult;
char* lpMem = NULL;

s_ProcessTable->hShareMemHandle = CreateFileMapping(INVALID_HANDLE_VALUE , NULL , PAGE_READWRITE|SEC_COMMIT , 0 , nSize , (LPCWSTR)"_SHAREMEM_");

if((NULL == s_ProcessTable->hShareMemHandle) || (INVALID_HANDLE_VALUE == s_ProcessTable->hShareMemHandle)) {

cout << "Create Share Memory fail" << endl;

return 0;
}
else {

nResult = GetLastError(); // 获取创建共享内存的错误信息
lpMem = (char *)MapViewOfFile(s_ProcessTable->hShareMemHandle ,
FILE_MAP_READ | FILE_MAP_WRITE , 0 , 0 , 0);
if (nResult != ERROR_ALREADY_EXISTS) // 如果同名的共享内存不存在
{
//第一次打开共享内存,需要初始化为零
memset(lpMem , 0 , nSize);

cout << "Create Share Memory Firstly" << endl;
}
}

// 返回共享内存空间首地址
return lpMem;
}


// 初始化共享内存,将共享内存空间连接到系统表的空闲块链表上
unsigned short ShareMem :: ShareMemInit() {

unsigned int nSize;
_MemoryBlock* FreeBlock;

nSize = 10 * 1024 * 1024;

s_ProcessTable = new _ProcessTable();

s_ProcessTable->lpShareMemTable = (_ShareMemTable *)CreatShareMem(nSize);


if (s_ProcessTable->lpShareMemTable) {

// 判断lpShareMemTable是否初始化过
if (! s_ProcessTable->lpShareMemTable->bInit) {

s_ProcessTable->lpShareMemTable->bInit = true;

// 将除去_ShareMemTable结构后剩下的共享内存大小作为一个空闲块连接到s_ProcessTable->lpShareMemTable->FreeBlockList下
FreeBlock = (_MemoryBlock*)(s_ProcessTable->lpShareMemTable + sizeof(_ShareMemTable));
s_ProcessTable->lpShareMemTable->nSize = nSize - sizeof(_ShareMemTable);

FreeBlock->nSize = nSize - sizeof(_ShareMemTable);

// 将空闲块链表形成双向循环链表
//*** 第一个进程启动后单步观察下列语句执行完后成功形成双向循环链表,
//但是后面的进程因为共享内存以创建完毕并完成初始化,
//因此不用执行下列语句,单步观察后面的进程FreeBlockList并没有形成双向循环。
s_ProcessTable->lpShareMemTable->FreeBlockList.Next = &FreeBlock->Item;
s_ProcessTable->lpShareMemTable->FreeBlockList.Prev = &FreeBlock->Item;
FreeBlock->Item.Next = &s_ProcessTable->lpShareMemTable->FreeBlockList;
FreeBlock->Item.Prev = &s_ProcessTable->lpShareMemTable->FreeBlockList;
}

return 1;
}

return 0;
}


ShareMem :: ShareMem () {

ShareMemInit();
}




在应用进程的工程中依赖上述ShareMem工程,并在应用中创建ShareMem:


ShareMem *lpShareMem;
lpShareMem = new ShareMem();




当第一个应用进程正常创建并初始化后,观察第二个应用进程的FreeBlockList并没有形成环形链表。
而且第一个进程和第二个进程的FreeBlockList地址还不一样,但是FreeBlockList.Next指向的地址却是一样的,再往后第一个进程的FreeBlockList.Next.Next就可以形成环了,而第二个进程FreeBlockList.Next.Next却是空指针。
是不是由于代码中都是直接使用指针以及取址操作符,而只对虚拟地址进行操作,还应该将虚拟地址映射到物理地址?

各位大神这是什么问题? 应该怎么解决??











...全文
810 1 打赏 收藏 转发到动态 举报
写回复
用AI写文章
1 条回复
切换为时间正序
请发表友善的回复…
发表回复
hoopool 2015-10-12
  • 打赏
  • 举报
回复
已经解决了,原因是共享不支持指针地址操作,个进程空间的虚拟地址映射都不同,所以会错误。

5,530

社区成员

发帖
与我相关
我的任务
社区描述
C/C++ 模式及实现
社区管理员
  • 模式及实现社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧