以同样的名字申请不同大小的共享内存中出现的问题
1、当我们使用CreateFileMapping时,我们告诉系统文件映射对象需要多大的物理存储器,此时会返回一个句柄给调用线程,这个句柄用来标识所创建的文件映射对象,
2、第二步我们需要使用MapViewOfFile.用来为文件的数据预订一块地址空间区域并将文件的数据作为物理存储器调拨给区域。将文件的数据映射到进程的地址空间
分析:首先我们一般会先创建一个共享内存的内核对象。Write之后然后用Read从共享中读取数据,在读取的时候我们会释放对象,也就是这个句柄,但是很不好意思,实际上,这个操作并不是我们想的这么美好,我们在open的时候会再返回一个句柄,尽管指的都是同一块内存,但是句柄的值是不一样的。当我们在read中读取之后并释放这个句柄的时候,只是我们open回来的句柄被我们关闭了,(当然我们会将句柄置为null)。所以其实在读取并关闭之后Create中创建的句柄还在。
于是我们想是不是可以在Write的函数中在打开的时候查看是不是存在,若是存在则关闭句柄。但是在open之后还会返回一个新的句柄值,尽管它们都指向的是同一块内存。
上面述说的事情,或许在每次都读取一样大小的数据是没有问题的,但是一旦我们向共享内存中写入的数据大小不一样的时候,应该说是更大的数据时候。通常我们创建之前会判断是否存在,然后关闭,再创建,可惜,这个再次创建的还是之前的,因为在内核对象中,若是对象的名字是一样的是不会再次创建的,而只是调用而已。于是这个内存的数据大小还是最初创建的1024个字节。现在我们要写入3000的数据,于是在memcpy中就会访问非法的地址。
这个问题整整困扰了我两天,我分析程序中每一个使用共享内存的地方,担心没有设置互斥。但是都正确,最后迫不得已使用了一个ProcessExplore的软件查看发现还有没有关闭的,现在问题发现了,那就好办了,直接的查找同名的,切记在读取数据中操作是达不到效果的,因为写与读会发生在两个不同的进程中,所以在写入数据的前面进行这一项的操作。
int WriteDataToMap(char *strMapName,int size,char *&buf)
{
DWORD dwMapsize=18+size;
for(int i=0;i<g_Maps&&i<200;i++)
{
if(strcmp(strMapName,g_StrMap[i].nm)==0)
{
CloseHandle(g_StrMap[i].hdl);
memset(g_StrMap[i].nm,0,100);
g_StrMap[i].hdl=NULL;
g_Maps--;
}
}
HANDLE hDbMap=OpenFileMapping(FILE_MAP_READ, FALSE, strMapName);
if (GetLastError() == ERROR_ALREADY_EXISTS)
{
printf("文件%s已经存在.\n",strMapName);
CloseHandle(hDbMap);
hDbMap=NULL;
}
hDbMap=CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE , 0, dwMapsize, strMapName);
if(hDbMap!=NULL)
{
if (GetLastError() == ERROR_ALREADY_EXISTS)
{
printf("文件%s已经存在.\n",strMapName);
CloseHandle(hDbMap);
hDbMap=NULL;
return -2;
}
else
{
LPBYTE lpData = (LPBYTE)MapViewOfFile(hDbMap, FILE_MAP_WRITE, 0, 0, 0);
if (lpData == NULL)//映射未成功
{
printf("文件映射失败");
CloseHandle(hDbMap);
hDbMap=NULL;
return -1;
}
g_Maps++;
memcpy(g_StrMap[g_Maps-1].nm,strMapName,100);
g_StrMap[g_Maps-1].hdl=hDbMap;
memset(lpData,0,dwMapsize);
memcpy(lpData,&hDbMap,sizeof(HANDLE));
memcpy(lpData+sizeof(HANDLE),&size,sizeof(int));
memcpy(lpData+sizeof(int)+sizeof(HANDLE), buf,size );
UnmapViewOfFile(lpData);
}
}
return 1;
}
int ReadDataFromMap(char *pMapName,char *&lpbReceive)
{
LPBYTE lpbReceiveBuf;
int size=0;
HANDLE hReceiveMap = OpenFileMappingA(FILE_MAP_READ, FALSE, pMapName);
if (hReceiveMap!=NULL)
{
g_Maps++;
g_StrMap[g_Maps-1].hdl=hReceiveMap;
memcpy(g_StrMap[g_Maps-1].nm,pMapName,100);
lpbReceiveBuf = (LPBYTE)MapViewOfFile(hReceiveMap,FILE_MAP_READ,0,0,0);//将内存区域映射到进程地址空间中
if (lpbReceiveBuf == NULL)
{
CloseHandle(hReceiveMap);
hReceiveMap=NULL;//关闭内核对象,仅仅closeHandle是不够的,因为在进程句柄表中,这一项还是存在的,下次利用的时候
//不知道会是什么对象,它只是一个索引而已。tj理解
return -2;
}
HANDLE ldh;
int n=0;
memcpy(&ldh,lpbReceiveBuf+n,sizeof(HANDLE));//句柄
n+=sizeof(HANDLE);
memcpy(&size,lpbReceiveBuf+n,sizeof(int));//长度
lpbReceive=new char[sizeof(int)+size+sizeof(HANDLE)];//分别为地址,长度
if(lpbReceive!=0)
{
if(size>0)
memcpy(lpbReceive,lpbReceiveBuf+sizeof(HANDLE),sizeof(int)+size);//具体数据
}
UnmapViewOfFile(lpbReceiveBuf);
}
return size;
}