windows下利用文件映射实现共享内存的办法比较简单,下面是实现代码,细节用注释说明.
调用类似linux下shm的操作.该类没有进行太多的测试,欢迎提出问题和bug~~:)
#include <windows.h>
#include <string>
#include <iostream>
#include <assert.h>
using std::string;
using std::cout;
using std::endl;
#pragma warning(disable: 4311)
class shareMemory
{
private:
LPWSTR shm_name_u;
bool is_create_file;
void * sh_base;
HANDLE semaphore;
HANDLE file_mapping;
int addr_len;
public:
/*create_file用来说明是用磁盘文件映射还是页文件映射,如果用磁盘文件映射,共享内存不会出现存储器release后出现违规访问的问题,但是会在磁盘上建立一个文件,文件的名称由参数shm_name给定.如果用页文件映射,则不会在磁盘上建立一个文件*/
shareMemory(const string& shm_name, bool create_file=false):is_create_file(create_file)
{
const char * _c_shm_name = shm_name.c_str();
int _size =(int)shm_name.length()+1;
shm_name_u=(LPWSTR)malloc(_size*2);
MultiByteToWideChar(CP_ACP,0,_c_shm_name,_size,shm_name_u,_size);
semaphore = CreateSemaphore(NULL,1,1,NULL);
sh_base = NULL;
file_mapping = INVALID_HANDLE_VALUE;
}
void * shm_open(void* addr,const int length, DWORD protect)
{ addr_len = length;
HANDLE _file_handle = INVALID_HANDLE_VALUE;
if(is_create_file)
{
_file_handle=
CreateFile(shm_name_u,GENERIC_READ|GENERIC_WRITE,0,
NULL,OPEN_ALWAYS,FILE_ATTRIBUTE_NORMAL,0);
#ifdef _DEBUG
if(_file_handle==INVALID_HANDLE_VALUE)
cout<<"can not create file! we use page file instead!";
#endif //end _DEBUG
}
/*打开指定名称的文件映射,如果不存在则创建一个*/
file_mapping = OpenFileMapping(PAGE_READWRITE,false,shm_name_u );
if(file_mapping!=NULL)
goto file_mapping_exist;
file_mapping =
CreateFileMapping(_file_handle,NULL,PAGE_READWRITE,
0,length,shm_name_u);
#ifdef _DEBUG
assert(file_mapping);
#endif
if(file_mapping==NULL)
return NULL;
file_mapping_exist:
sh_base = MapViewOfFileEx(file_mapping,protect,0,0,length,addr);
CloseHandle(_file_handle);
return sh_base;
}
/*往共享内存中写数据,返回写出数据的字节个数*/
int shm_write(void *dest, void * src, int size)
{
if(!check_adress(dest))
return -1;
int _write_count = (int)sh_base+addr_len - (int)dest;
if(_write_count>size)
_write_count = size;
/*利用semaphore进行保护映射的区域(同一进程的不同线程调用时候才进行保护)*/
WaitForSingleObject(semaphore,INFINITE);
memcpy(dest,src,_write_count);
ReleaseSemaphore(semaphore,1,NULL);
FlushViewOfFile(sh_base,_write_count);
return _write_count;
}
/*从共享内存中读数据,返回读出的数据字节个数*/
int shm_read(void* src, void * dest, int size)
{
if(!check_adress(src))
return -1;
int _read_count = (int)sh_base+addr_len -(int) src;
if(_read_count>size)
_read_count = size;
memcpy(dest,src,_read_count);
return _read_count;
}
~shareMemory()
{
UnmapViewOfFile(sh_base);
free(shm_name_u);
CloseHandle(semaphore);
CloseHandle(file_mapping);
}
private :
/*进行地址检测*/
bool check_adress(void* addr)
{
if( ( (int)addr <(int)sh_base) || ((int)addr > (int)sh_base+addr_len) )
{
SetLastError(ERROR_ACCESS_DENIED);
#ifdef _DEBUG
printf("access denied,the destination address out of the map view!");
#endif //_DEBUG
return false;
}
return true;
}
};
测试:
写进程的主函数:
int main()
{
shareMemory sm("boost", false);
void * bs = sm.shm_open(NULL,1000*4,FILE_MAP_WRITE);
if(bs==NULL)
return -1;
int a[10];
for(int i=0; i<10; ++i)
a[i] = i;
sm.shm_write(bs,a,10*4);
Sleep(100000);
}
读进程的主函数:
int main()
{
shareMemory sm("boost", false);
void * bs = sm.shm_open(NULL,1000,FILE_MAP_READ);
if(bs==NULL)
{ cout<<"null";
return -1;
}
int b[10];
sm.shm_read(bs,b,10*4);
for(int i=0; i<10; ++i)
cout<<b[i]<<" ";
}