windows下利用文件映射实现共享内存

来源:互联网 发布:linux查看iscsi盘符 编辑:程序博客网 时间:2024/05/18 00:37

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]<<"  ";
}

原创粉丝点击