精华内容
下载资源
问答
  • Windows共享内存

    2013-07-09 11:01:04
    Windows共享内存可以让两个进程对同一块内存进行读写。 以下有2个进程,a.cpp生成A进程,b.cpp生成b进程。那么a进程将不停地读名为"Global\\MyFileMappingObject"的共享内存块,而b进程不停地写名为"Global\\...


     

    Windows共享内存可以让两个进程对同一块内存进行读写。

    以下有2个进程,a.cpp生成A进程,b.cpp生成b进程。那么a进程将不停地读名为"Global\\MyFileMappingObject"的共享内存块,而b进程不停地写名为"Global\\MyFileMappingObject"的共享内存块。从而实现IPC。

     

    复制代码
    //a.cpp
    #include <windows.h>
    #include <string.h>
    #include <string>
    #include <iostream>
    #include <tchar.h>
    using namespace std;
    
    #define BUF_SIZE 256
    TCHAR szName[]=TEXT("Global\\MyFileMappingObject");    //指向同一块共享内存的名字
    
    int main(int argc, char *argv[])
    {
        HANDLE hMapFile;
        LPCTSTR pBuf;
    
        hMapFile = CreateFileMapping(
            INVALID_HANDLE_VALUE,    // use paging file
            NULL,                    // default security
            PAGE_READWRITE,          // read/write access
            0,                       // maximum object size (high-order DWORD)
            BUF_SIZE,                // maximum object size (low-order DWORD)
            szName);                 // name of mapping object
    
        if (hMapFile == NULL)
        {
            _tprintf(TEXT("Could not create file mapping object (%d).\n"),
                GetLastError());
            return 1;
        }
        pBuf = (LPTSTR) MapViewOfFile(hMapFile,   // handle to map object
            FILE_MAP_ALL_ACCESS, // read/write permission
            0,
            0,
            BUF_SIZE);
    
        if (pBuf == NULL)
        {
            _tprintf(TEXT("Could not map view of file (%d).\n"),
                GetLastError());
    
            CloseHandle(hMapFile);
    
            return 1;
        }
        //从main开始至此,A B process代码一样,都是获取名为"Global\\MyFileMappingObject"的共享内存的指针
    
        //以下代码,A不停地读共享内存pBuf
        while(1)
        {
            cout<<pBuf<<endl;
            cout<<"A process: hit keyboard to receive from B process"<<endl;
            getchar();
        }
    
        UnmapViewOfFile(pBuf);
        CloseHandle(hMapFile);
        return 0;
    }
    复制代码

     

     

     

    复制代码
    //b.cpp
    #include <iostream>
    #include <Windows.h>
    #include <tchar.h>
    using namespace std;
    
    #define BUF_SIZE 256
    TCHAR szName[]=TEXT("Global\\MyFileMappingObject");    //指向同一块共享内存的名字
    
    int main()
    {
        HANDLE hMapFile;
        LPCTSTR pBuf;
    
        hMapFile = CreateFileMapping(
            INVALID_HANDLE_VALUE,    // use paging file
            NULL,                    // default security
            PAGE_READWRITE,          // read/write access
            0,                       // maximum object size (high-order DWORD)
            BUF_SIZE,                // maximum object size (low-order DWORD)
            szName);                 // name of mapping object
    
        if (hMapFile == NULL)
        {
            _tprintf(TEXT("Could not create file mapping object (%d).\n"),
                GetLastError());
            return 1;
        }
        pBuf = (LPTSTR) MapViewOfFile(hMapFile,   // handle to map object
            FILE_MAP_ALL_ACCESS, // read/write permission
            0,
            0,
            BUF_SIZE);
    
        if (pBuf == NULL)
        {
            _tprintf(TEXT("Could not map view of file (%d).\n"),
                GetLastError());
    
            CloseHandle(hMapFile);
    
            return 1;
        }
        //从main开始至此,A B process代码一样,都是获取名为"Global\\MyFileMappingObject"的共享内存的指针
    
        //以下代码,B不停写共享内存pBuf
        while(1)
        {
            TCHAR s[BUF_SIZE];
            cout<<"B process: plz input sth. to be transfered to A process."<<endl;
            cin>>s;
            memcpy((PVOID)pBuf, s, BUF_SIZE);
        }
    }
    展开全文
  • windows 共享内存

    千次阅读 2014-07-10 10:45:26
    父例程: 创建内存

    ----------------------------------------父例程:创建内存块----------------------------------------------

    ShareMemory.h

    #pragma once
    
    #include <Windows.h>
    #include <tchar.h>
    
    const DWORD ERROR_NOT_CREATE = 0x66001;
    
    class CShareMemory
    {
    public:
    	CShareMemory(void);
    	virtual ~CShareMemory(void);
    
    	DWORD Create(const TCHAR *pName, DWORD dwMaximumSizeLow,  
    				 DWORD dwMaximumSizeHigh = 0, 
    				 DWORD flProtect = PAGE_READWRITE, 
    				 LPSECURITY_ATTRIBUTES lpAttributes = NULL);
    	DWORD Write(byte *pbData, DWORD dwLength, 
    				DWORD dwOffsetLow = 0, 
    				DWORD dwOffsetHigh = 0);
    	DWORD Read(byte *pbBuf, DWORD dwLength, 
    			   DWORD dwOffsetLow = 0, 
    			   DWORD dwFileOffsetHigh = 0);
    	void  Close(void);
    	DWORD SetAccess(DWORD dwDesiredAccess = FILE_MAP_ALL_ACCESS);
    private:
    	TCHAR *m_pName;
    	HANDLE m_hShareMemory, m_hAccessMutex;
    	BOOL m_bCreate;
    	byte *m_pView;
    };<strong>
    </strong>



    ShareMemory.cpp

    #include "ShareMemory.h"
    
    CShareMemory::CShareMemory(void)
    : m_pName(NULL), m_pView(NULL), m_hShareMemory(NULL), m_hAccessMutex(NULL), 
      m_bCreate(FALSE)
    {
    	m_pView = new byte;
    }
    
    CShareMemory::~CShareMemory(void)
    {
    	Close();
    }
    
    DWORD CShareMemory::Create(const TCHAR *pName, DWORD dwMaximumSizeLow, 
    						   DWORD dwMaximumSizeHigh, DWORD flProtect, 
    						   LPSECURITY_ATTRIBUTES lpAttributes)
    {
    	if (pName == NULL)
    	{
    		return ERROR_INVALID_PARAMETER;
    	}
    	
    	m_pName = new TCHAR[_tcslen(pName)+1];
    	_tcscpy(m_pName, pName);
    	m_pName[_tcslen(pName)] = TEXT('\0');
    
    	m_hShareMemory = CreateFileMapping(INVALID_HANDLE_VALUE, 
    									   lpAttributes, 
    									   flProtect, 
    									   dwMaximumSizeHigh, 
    									   dwMaximumSizeLow, 
    									   m_pName);
    	if (m_hShareMemory == NULL)
    	{
    		return GetLastError();
    	}
    
    	TCHAR *pMtx = new TCHAR[_tcslen(pName)+4];
    	_tcscpy(pMtx, m_pName);
    	pMtx[_tcslen(m_pName)] = TEXT('\0');
    	_tcscat(pMtx, TEXT("Mtx"));
    	pMtx[_tcslen(pName)+3] = TEXT('\0');
    	m_hAccessMutex = CreateMutex(lpAttributes, FALSE, pMtx);
    	if (m_hAccessMutex == NULL)
    	{
    		return GetLastError();
    	}
    
    	m_pView = (byte*)MapViewOfFile(m_hShareMemory, 
    							       FILE_MAP_ALL_ACCESS, 
    								   0, 
    								   0, 
    								   0);
    	if (m_pView == NULL)
    	{
    		return GetLastError();
    	}
    	memset(m_pView, '\0', dwMaximumSizeLow);
    	m_bCreate = TRUE;
    
    	return 0;
    }
    
    DWORD CShareMemory::Write(byte *pbData, DWORD dwLength, 
    						  DWORD dwOffsetLow,
    						  DWORD dwOffsetHigh)
    {
    	DWORD dwErr(0);
    	
    	dwErr = WaitForSingleObject(m_hAccessMutex, INFINITE);
    	if (dwErr != 0)
    	{
    		return dwErr;
    	}
    
    	memcpy(m_pView+dwOffsetLow, pbData, dwLength);
    	ReleaseMutex(m_hAccessMutex);
    
    	return 0;
    }
    
    DWORD CShareMemory::Read(byte *pbBuf, DWORD dwLength, 
    						 DWORD dwOffsetLow, DWORD dwFileOffsetHigh)
    {
    	DWORD dwErr(0);
    
    	dwErr = WaitForSingleObject(m_hAccessMutex, INFINITE);
    	if (dwErr != 0)
    	{
    		return dwErr;
    	}
    
    	memcpy(pbBuf, m_pView+dwOffsetLow, dwLength);
    	ReleaseMutex(m_hAccessMutex);
    
    	return 0;
    }
    
    void CShareMemory::Close(void)
    {
    	if (m_bCreate)
    	{
    		delete [] m_pName;
    		UnmapViewOfFile(m_pView);
    		//delete m_pView;
    		CloseHandle(m_hShareMemory);
    		CloseHandle(m_hAccessMutex);
    
    		m_bCreate = FALSE;
    	}
    }
    
    DWORD CShareMemory::SetAccess(DWORD dwDesiredAccess)
    {
    	if (!m_bCreate)
    	{
    		return ERROR_NOT_CREATE;
    	}
    	DWORD dwErr(0);
    
    	dwErr = WaitForSingleObject(m_hAccessMutex, INFINITE);
    	if (dwErr != 0)
    	{
    		return dwErr;
    	}
    	UnmapViewOfFile(m_pView);
    	m_pView = (byte*)MapViewOfFile(m_hShareMemory, 
    	  							   FILE_MAP_ALL_ACCESS, 
    								   0, 
    								   0, 
    								   0);
    	ReleaseMutex(m_hAccessMutex);
    	if (m_pView == NULL)
    	{
    		return GetLastError();
    	}
    
    	return 0;
    }

    main.cpp


    #include "ShareMemory.h"
    #include <iostream>
    
    using namespace std;
    
    void _tmain()
    {
    	cout<<"-----windows 共享内存父例程------------"<<endl<<endl;
    	DWORD dwErr;
    	CShareMemory sm;
    	dwErr = sm.Create(TEXT("TESTSM"), 512);
    	char *pIn = new char[256];
    	char *pOut = new char[256];
    	cin>>pIn;
    	dwErr = sm.Write((byte*)pIn, strlen(pIn));
    	dwErr = sm.Read((byte*)pOut, 100);
    	//char *p;// = (char*)pOut;
    	cout<<(char*)pOut<<endl;
    	cin>>pIn;
    	delete [] pIn;
    	delete [] pOut;
    }


    ----------------------------------------子例程:分享父例程创建的内存块----------------------------------------------



    // shareMemery_test.cpp : Defines the entry point for the console application.
    //
    
    #include "stdafx.h"
    #include <iostream>
    #include <Windows.h>
    using namespace std;
    
    
    int _tmain(int argc, _TCHAR* argv[])
    {
    
    
    	cout<<"------windows 共享内存子例程--------------------"<<endl<<endl;
    
    	HANDLE handle=::OpenFileMapping(FILE_MAP_ALL_ACCESS,FALSE,_T("TESTSM"));
    
    
    	char* szShareMem = new char[256];
    	szShareMem   =   (char*)::MapViewOfFile(handle,FILE_MAP_ALL_ACCESS,0,0,0); 
    
    	cout<<szShareMem<<endl<<endl;
    
    	UnmapViewOfFile(szShareMem);delete [] szShareMem;
    	CloseHandle(handle);
    	system("pause");
    	return 0;
    }
    



    效果如下:




    展开全文
  • windows共享内存

    万次阅读 2010-01-06 23:59:00
    共享内存在 Windows 中是用 FileMapping 实现的。我们可以用 CreateFileMapping 创建一个内存文件映射对象, CreateFileMapping 这个 API 将创建一个内核对象,用于映射文件到内存。这里,我们并不需要一个实际的...

    共享内存在   Windows   中是用   FileMapping   实现的。我们可以用   CreateFileMapping   创建一个内存文件映射对象,   CreateFileMapping   这个   API   将创建一个内核对象,用于映射文件到内存。这里,我们并不需要一个实际的文件,所以,就不需要调用   CreateFile   创建一个文件,   hFile   这个参数可以填写   INVALID_HANDLE_VALUE   。但是,文件长度是需要填的。Windows   支持长达   64bit   的文件,但是这里,我们的需求一定不会超过   4G   ,   dwMaximumSizeHigh   一定是   0   ,长度填在   dwMaximumSizeLow   即可。然后调用   MapViewOfFile   映射到当前进程的虚拟地址上即可。一旦用完共享内存,再调用   UnmapViewOfFile   回收内存地址空间。  
       
      Windows   把   CreateFileMapping   和   MapViewOfFile   两个   API   分开做是有它的道理的。这是因为允许映射一个超过   4G   的文件,而地址空间最大只有   4G   (实际上,一般用户的程序只能用到   2G)   ,   MapViewOfFile   就可以指定文件的   Offset   而只映射一部分。  
       
      在   CreateFileMapping   的最后一个参数   pszName   填写一个名字,那么别的进程就可以用这个名字去调用   OpenFileMapping   来打开这个   FileMapping   对象,在新的进程内作映射。   不过,通过约定字符串的方法似乎不太优雅。  
       
      一个优雅的方法是,用   DuplicateHandle   在新进程中复制一份   FileMapping   对象出来,然后想办法把   Handle   通知新进程,比如用消息的方式传递过去。  
       
      如果需要共享内存的两个进程是父子关系,那么我们可以不用消息传递的方式来通知   FileMapping   的   Handle   。父进程可以用继承   Handle   的方式直接把   FileMapping   的   Handle   传递到子进程中。当然,在   CreateFileMapping   时就应该设置可以被继承的属性。  
       
      大约是这样:  
       
      SECURITY_ATTRIBUTES   sa;  
      sa.nLength=sizeof(sa);  
      sa.lpSecurityDescriptor=NULL;  
      sa.bInheritHandle=TRUE;  
      handle=CreateFileMapping(INVALID_HANDLE_VALUE,&sa,PAGE_READWRITE,0,size,NULL);  
       
      这样,在   CreateProcess   的时候,如果   bInheritHandles   参数为   TRUE   ,所有有可被继承属性的内核对象都会被复制到子进程中。  
       
      注:内核对象的继承就是在   CreateProcess   创建子进程,但是子进程的主线程尚未活动之前,内核扫描当前进程中所有内核对象,检查出有可继承属性的那些,再用   DuplicateHandle   复制一份到子进程。由于是内核对象,在内核中实质只有一份,所有只是引用记数加一,父进程和子进程对同一内核对象的   Handle   一定是相同的。  
       
      复制内核对象的过程是由   CreateProcess   内部完成的,我们可以放心的把对象   Handle   (和子进程相同)   通过命令行传递给子进程。或者,用环境变量传递也可以。  
       
      值得注意的是,子进程用完了这个   FileMapping   对象后一样需要   CloseHandle   减去引用计数。  
       
      备注:  
      CreateProcess   调用时,pszCommandLine   不能直接填上一个不可修改的字符串。例如:  
       
      CreateProcess("test.exe","test   argument",...);  
       
      这样就是错误的,因为   "test   argument"   会被编译器编译放到不可修改的数据段中。正确的方法是:  
       
      char   cmdline[]="test   argument";  
      CreateProcess("test.exe",cmdline,...);  
       
      这样,命令行的字符串就被放在堆栈上,是可以被读写的。  
       
      CreateProcess   的倒数第二个参数需要填写一个   STARTUPINFOW   结构,这个结构很复杂,通常填起来很麻烦。我们可以复制一份父进程的结构,再酌情修改。方法是:  
       
      STARTUPINFO   si={sizeof(si)};  
      PROCESS_INFORMATION   pi;  
      GetStartupInfo(&si);  
      CreateProcess(...,&si,&   pi);   
          这里,   STARTUPINFO   结构的第一个长度信息通常应该填上,保证   GetStartupInfo(&si);   的正确执行。 

    下面是另一个人写的

    通过windows api我们可以很容易的在内存中创建这么一个区域并轻易的读取它。这里需要用到两个关键的api函数:CreateFileMapping和MapViewOfFile,前者在内存中创建一个内存映象区,它需要一些参数包括这块区域的读写权限,唯一区域名称以及数据大小(这些参数将在下面代码的注释中给予说明,更多的参数说明请参看win sdk的帮助文件或查看msdn);后者返回一个指向这块区域的指针以便在程序中调用。下面我们将通过一个简单的例子来说明,这个例子由两个工程组成,一个通过一个按纽负责向内存映象区写入一个长度为11个字符的字符串(‘how are you‘,通过一个edit读入,如果edit中的字符数大于了11个程序将可能出错),另一个则通过一个按纽读出这个字符串,写入一个edit中。下面是部分的代码(为了节省篇幅,加上程序很简单,有些不会影想你阅读的代码没有贴出):

    我们首先在第一个工程(窗口取名为SetValue)的单元的接口部分声明一个指向即将创建的内存区域的句柄和一个用来向这个区域写数据的指针变量:

    var

      ……

      hFileMapping:HWND;//指向内存区域的句柄

      SetString:pchar;//这里应该使用标准的windows字符串而非delphi特有的string类型

    这样我们可以在按纽的单击事件中编写相应的代码:

    procedure TForm1.Button1Click(Sender: TObject);

    begin

     hFileMapping:=CreateFileMapping($FFFFFFFF,nil,Page_ReadWrite,0,11,'MapString');

     //$FFFFFFFF表示使用虚拟文件,注意两个工程中应该使用同一个唯一的名称MapString

     if hFileMapping=0 then

      raise Exception.Create('Error creating map file!');

     SetString:=MapViewOfFile(hFileMapping,File_Map_Write,0,0,11);

     strcopy(SetString,pchar(Edit1.Text));

     //注意这里应该使用拷贝函数而不是直接赋值 SetString:=pchar(Edit1.Text)

    end;

    当然,我们还可以在这个主工程中编写一个释放内存映象的过程:

    procedure TForm1.Button2Click(Sender: TObject);

    begin

     UnMapViewOfFile(SetString);

     if hFileMapping<>0 then

      closehandle(hFileMapping);

    end;

    接下来是第2个工程的按纽单击事件,它和第一个工程几乎没有什么不同,只是我们修改了内存映象的读取权限为只读而以:

    var

      ……

      GetString:pchar;

      hMapFileMaping:HWND;

    procedure TForm1.Button1Click(Sender: TObject);

    begin

     hMapFileMaping:=CreateFileMapping($FFFFFFFF,nil,Page_ReadOnly,0,11,'MapString');

    //再次注意一定要使用唯一的名称(MapString)和第一个工程保持一致

     if hMapFileMaping=0 then

      raise Exception.Create('Error');

     GetString:=MapViewOfFile(hMapFileMaping,File_Map_Read,0,0,11);

     Edit1.Text:=String(GetString);

    end; 

    展开全文
  • 简单windows共享内存封装类

    千次阅读 2016-09-21 10:10:53
    简单windows共享内存封装类

    在维护公司的一个项目的时候发现了一个共享内存类,看了一下注释,发现是chrome里头的代码,所以就把chrome的代码翻出来看了一个,果然写的不错,考虑的情况也确实比较多,想想之前看过了《windows核心编程》这本书也有讲,所以就把书中的相关章节又看了一遍,写这篇文章就算是一个总结吧

    先上代码:

     

     

    #include <Windows.h>
    #include <string>
    #include <process.h>
    
    
    class SharedMemory
    {
    public:
        SharedMemory(BOOL bReadOnly = FALSE) : m_hLock(NULL),
            m_hFileMap(NULL),
            m_pMemory(NULL),
            m_bReadOnly(FALSE),
            m_dwMappedSize(0),
            m_strName(L"")
        {
        
        }
    
        BOOL Create(const std::wstring& strName, DWORD dwSize)
        {
            if (dwSize <= 0)
                return FALSE;
    
            HANDLE handle = ::CreateFileMappingW(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, dwSize, strName.empty() ? NULL : strName.c_str());
            if (!handle)
                return FALSE;
    
            // 已经存在了
            if (GetLastError() == ERROR_ALREADY_EXISTS)
            {
                Close();
                return FALSE;
            }
    
            m_hFileMap = handle;
            m_dwMappedSize = dwSize;
            return TRUE;
        }
    
        BOOL Open(const std::wstring& strName, BOOL bReadOnly)
        {
            m_hFileMap = ::OpenFileMappingW(bReadOnly ? FILE_MAP_READ : FILE_MAP_ALL_ACCESS, FALSE, strName.empty() ? NULL : strName.c_str());
            if (!m_hFileMap)
                return FALSE;
    
            m_bReadOnly = bReadOnly;
            return TRUE;
        }
    
        BOOL MapAt(DWORD dwOffset, DWORD dwSize)
        {
            if (!m_hFileMap)
                return FALSE;
    
            if (dwSize > ULONG_MAX)
                return FALSE;
    
            ULARGE_INTEGER ui;
            ui.QuadPart = static_cast<ULONGLONG>(dwOffset);
    
            m_pMemory = ::MapViewOfFile(m_hFileMap,
                m_bReadOnly ? FILE_MAP_READ : FILE_MAP_ALL_ACCESS, ui.HighPart, ui.LowPart, dwSize);
    
            return ( m_pMemory != NULL );
        }
    
        void Unmap()
        {
            if (m_pMemory)
            {
                ::UnmapViewOfFile(m_pMemory);
                m_pMemory = NULL;
            }
        }
    
        LPVOID GetMemory() const { return m_pMemory; }
    
        HANDLE GetHandle() const
        {
            return m_hFileMap;
        }
    
        // 锁定共享内存
        BOOL Lock(DWORD dwTime)
        {
            // 如果还没有创建锁就先创建一个
            if (!m_hLock)
            {
                std::wstring strLockName = m_strName;
                strLockName.append(L"_Lock");
                // 初始化的时候不被任何线程占用
                m_hLock = ::CreateMutexW(NULL, FALSE, strLockName.c_str());
                if (!m_hLock)
                    return FALSE;
            }
    
            // 哪个线程最先调用等待函数就最先占用这个互斥量
            DWORD dwRet = ::WaitForSingleObject(m_hLock, dwTime);
            return (dwRet == WAIT_OBJECT_0 || dwRet == WAIT_ABANDONED);
        }
    
        void Unlock()
        {
            if (m_hLock)
            {
                ::ReleaseMutex(m_hLock);
            }
        }
    
        SharedMemory::~SharedMemory() 
        {
            Close();
            if (m_hLock != NULL)
            {
                CloseHandle(m_hLock);
            }
        }
    
        void Close()
        {
            Unmap();
    
            if (m_hFileMap)
            {
                ::CloseHandle(m_hFileMap);
                m_hFileMap = NULL;
            }
        }
    
    private:
        HANDLE m_hLock;
        HANDLE m_hFileMap;
        LPVOID m_pMemory;
        std::wstring m_strName;
        BOOL m_bReadOnly;
        DWORD m_dwMappedSize;
    
        SharedMemory(const SharedMemory& other);
        SharedMemory& operator = (const SharedMemory& other);
    };

     

     

     

     

     

    共享内存的原理:

    共享内存其实是一种特殊的文件映射对象,而文件映射对象本质上又是虚拟内存(这个知识点可以看《windows核心编程》或者在网上找资料了解学习一下)。

    虚拟内存一般是通过页交换文件来实现的,这个页交换文件是什么呢?一般就是我们C盘中的pagefile.sys文件,如下图所示:

     

     

    不过也有通过文件来实现的,比如我们双击exe文件,这时其实是用这个exe文件本身来作为虚拟内存来使用(参见《windows核心编程》中的讲解)。

    而内存映射文件实现原理也就是通过文件来实现虚拟内存的,实现原理和双击exe的原理是类似的。这个文件基本上可以是任意文件,打开之后作为虚拟内存映射到进程

    的地址空间中。

    我们先来大致看一下虚拟内存的使用过程吧:

    1. 在进程地址空间中预订区域(VirtualAlloc)

    2. 给区域调拨物理存储器(VirtualAlloc)

    3. 使用虚拟内存(memcpy等函数)

    4. 撤销调拨物理存储器,释放所预订的区域(VirtualFree)

    这里所说的物理存储器一般是指页交换文件(pagefile.sys)

     

    我们再来看一下内存映射文件的使用过程:

    1. 打开或者创建文件(CreateFile)

    2. 创建文件映射对象(CreateFileMapping)

    3. 映射文件视图(MapViewOfFile)

    4. 使用内存映射文件(memcpy等函数)

    5. 撤销文件视图(UnMapViewOfFile)

    6. 关闭映射文件句柄(CloseHandle)

     

    之前说内存映射文件本质上是虚拟内存,那么这两个过程又是怎么对应的呢?

    其实这两个过程基本上是一一对应的,只不过在上层使用的时候我们感觉不到而已。

    打开文件或创建文件可以看成是在准备虚拟内存的物理存储器。

    创建文件映射对象可以看成是预订区域

    映射文件试图可以看成是给区域调拨物理存储器,这个物理存储器就是之前打开或者创建的文件

    撤销文件视图可以看成是撤销调拨物理存储器

    关闭映射文件句柄可以看成是释放区域

    整个过程基本上就是这样。

     

    一个普通的文件映射对象的使用代码大致是这样子:

     

    HANDLE hFile = CreateFile(...)
    HANDLE hFileMap = CreateFileMapping(hFile, ...);
    PVOID pView = MapViewOfFile(hFileMap,FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 0);
    memcpy(pView, ...);
    UnmapViewOfFile(pView);
    CloseHandle(hFileMap);
    CloseHandle(hFile);


    而共享内存的代码有什么不同呢?

     

    主要区别是物理存储器不一样,普通的内存映射文件都是使用磁盘上的文件作为物理存储器,而共享内存使用的是也交换文件(pagefile.sys)。

    这个区别如何体现的代码上呢?就是在调用函数CreateFileMapping的时候第一个参数是INVALID_HANDLE_VALUE。

    整个过程基本上讲解完了,下面来分析一下SharedMemory这个类。

     

    我们要在不同的进程中进行共享,那么我们需要创建一个命名的对象(其他进程间通信方式有:粘贴板,Socket,WM_COPY消息,邮槽,管道等)。

    还有一个问题是需要在不同线程之间进行同步,否则数据有可能会乱套。这里使用了一个互斥量。

    现在顺便问一个问题,能用关键段吗?

    不能,因为关键段不能跨进程使用,而且这种场合使用需要一个等待时间,关键段也是不支持的。

    至于关键段和互斥量的具体区别也可以参见《windows核心编程》里头的讲解。

    代码中的Lock函数会让第一个调用的线程占有互斥量,第二个调用者等待,用起来也是比较方便。

     

    代码应该不用过多解释吧,下面来一下使用示例:

     

     

    #include <Windows.h>
    #include <string>
    #include <process.h>
    #include <tchar.h>
    
    #define MAP_FILE_NAME (L"Global\\TestName")
    #define MAP_SIZE (4*1024)
    #define STRING_BUF (L"helloword")
    
    UINT __stdcall ThreadFunc(LPVOID lParam)
    {
        SharedMemory *pSharedMemory = NULL;
        pSharedMemory = new SharedMemory();
        pSharedMemory->Lock(INFINITE);
        pSharedMemory->Open(MAP_FILE_NAME, FALSE);
        pSharedMemory->MapAt(0, MAP_SIZE);
        LPVOID pVoid = pSharedMemory->GetMemory();
        int length = wcslen(STRING_BUF);
        WCHAR *pbuf = new WCHAR[length + 1];
        
        memcpy(pbuf, pVoid, length*2);
        pbuf[length] = L'\0';
    
        pSharedMemory->Unlock();
        pSharedMemory->Close();
        delete[] pbuf;
        delete pSharedMemory;
        int i = 0;
        while(true)
            Sleep(5000);
        return 1;
    }
    
    int WINAPI wWinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nShowCmd )
    {
        SharedMemory *pSharedMemory = NULL;
        pSharedMemory = new SharedMemory();
        pSharedMemory->Lock(INFINITE);
        pSharedMemory->Create(MAP_FILE_NAME, MAP_SIZE);
        pSharedMemory->MapAt(0, MAP_SIZE);
        LPVOID pVoid = pSharedMemory->GetMemory();
        wcscpy((WCHAR*)pVoid, STRING_BUF);
        pSharedMemory->Unlock();
    
        _beginthreadex(NULL, 0, ThreadFunc, NULL, NULL, 0);
    
         Sleep(30000);
    
        delete pSharedMemory;
        
        return 0;
    }


    这里是在同一个进程的不同线程来测试的,用不同的进程也是没有问题的。

     

    每个线程在使用的时候一定要加锁解锁,否则就有可能出现数据不一致的问题。

    这个过程又一个很重要的问题,就是创建共享之后,不要调用Close函数把共享内存关闭了,这个过程在虚拟内存中相当于

    是否了申请的区域,如果这样的话其他进程就不能使用了,OpneFileMapping会失败,也就是不能共享数据了。

    之前发现OpenFileMapping失败了搞了半天才明白过来,看来之前对内存映射文件的理解还是不够深刻-_-

    注意,释放pSharedMemory的时候也调用了Close函数,所以要保证其他进程在通信过程中不要释放pSharedMemory指针。

     

    参考资料:

    1. 《windows核心编程》

    2. chrome源码中SharedMemory类的代码(在src\\base\\memory路径下)

    3. http://www.cnblogs.com/kex1n/archive/2011/08/10/2133389.html

     

     

    2020.5.1更新:

    评论区有些网友反映pVoid指针为空,那很可能是因为创建内存映射文件函数CreateFileMappingW调用失败了。

    因为在名称中我是这么写的:#define MAP_FILE_NAME (L"Global\\TestName")

    把全局命令空间前缀加上了,有些程序可能并没有权限去创建或者打开这样的内存映射文件导致。一般GetLastError会返回5,表示没有权限。解决办法可以把名称的Global\\去掉即可。

    展开全文
  • Windows共享内存示例

    千次阅读 2016-11-12 16:10:36
    Windows共享内存示例  共享内存主要是通过映射机制实现的。  Windows 下进程的地址空间在逻辑上是相互隔离的,但在物理上却是重叠的。所谓的重叠是指同一块内存区域可能被多个进程同时使用。当调用 ...
  • Windows共享内存解析

    千次阅读 2017-07-29 23:47:42
    Windows程序开发过程中,当多个进程之间需要使用同样的数据的时候我们最好的方式就是通过共享内存进行处理(比如:当A进程运行时,进行数据处理,那么此时我想知道数据是不是正确,用B监控,那么A与B之间就可以...
  • windows 共享内存加锁

    2016-12-14 09:39:08
    请问那位知道当时创建共享内存后有多个进程频繁访问同一块内存时需要加锁吗? 如果需要加锁,使用那个方法比较合适。
  • 一则简单的Windows共享内存IPC代码

    千次阅读 2016-02-25 16:45:51
    Windows共享内存可以让两个进程对同一块内存进行读写。 以下有2个进程,a.cpp生成A进程,b.cpp生成b进程。那么a进程将不停地读名为"Global\\MyFileMappingObject"的共享内存块,而b进程不停地写名为"Global\\...
  • windows 共享内存使用说明

    千次阅读 2012-07-23 13:52:45
    未完待续
  • Windows共享内存以及相关函数的使用

    千次阅读 2015-01-29 10:49:03
    程序与程序之间、进程与进程之间、线程与线程之间进行数据交互与...方法1:共享内存函数 CreateFileMapping HANDLE CreateFileMapping( HANDLE hFile, //物理文件句柄 LPSECURITY_ATTRIBUTES lpAttributes,
  • Windows共享内存 C++及C#实现

    千次阅读 2012-09-07 08:47:06
    FileMapping用于将存在于磁盘的文件放进一个进程的... Object(存放于物理内存中)用于维持这种映射关系,这样当多个进程需要读写那个文件的数据时,它们的File View其实对应的都是同一个File Mapping Object,这样做
  • windows共享内存操作

    千次阅读 2019-05-27 17:46:26
    windows共享内存 共享内存主要是通过映射机制实现的。windows下进程的地址空间在逻辑上是相互隔离的,但是在物理上确实相互重叠的。所谓的重叠是指同一块内存区域可能被多个进程同时使用。 在windows程序开发过程中...
  • windows使用共享内存实例

    千次阅读 2018-06-16 12:34:32
    今天复习一下windows下进程间通讯的方法:共享内存,以下是简单实例客户端:#include &lt;windows.h&gt; #include &lt;stdio.h&gt; #pragma pack(1) struct ShareData { int iType; int iSize; ...
  • windows共享内存

    千次阅读 2019-01-18 12:26:56
    //创建共享内存 #define BUF_SIZE_RES 1025 char szNameresult[] = "NameOfMappingshareresult";//名字作为标识 HANDLE hMapFileresult = CreateFileMapping( INVALID_HANDLE_VALUE, // 物理文件句柄...
  • windows下进程通讯有很多方式,跨设备通讯一般使用tcp udp,如果在同一台电脑上 使用 管道 和 共享内存还是比较方便的。 下面说下windows共享内存的使用。 进程一:(1)创建共享内存区域 #include <...
  • C++ windows共享内存

    2019-03-13 09:12:00
    共享内存 (也叫内存映射文件) 主要是通过映射机制实现的 , Windows 下进程的地址空间在逻辑上是相互隔离的 , 但在物理上却是重叠的 ; 所谓的重叠是指同一块内存区域可能被多个进程同时使用 , 当调用 ...
  • 一、共享内存 1、什么是共享内存共享内存,就是多个进程共用一块逻辑内存,每个进程均可对该内存进行读写,是实现进程间通信(本地通信)的一种方式。在Windows和linux平台均可实现,实现流程相似,但调用的函数...
  • 在网上看到说共享内存块的名字要加"Global\\",否则会使共享的内存只能在当前用户下被另一个或多个进程访问。 可是我在创建共享内存如下 ![图片说明]...
  • windows创建共享内存

    千次阅读 2011-04-12 14:29:00
    共享内存在 Windows 中是用 FileMapping 实现的。我们可以用 CreateFileMapping 创建一个内存文件映射对象, CreateFileMapping 这个 API 将创建一个内核对象,用于映射文件到内存。这里,我们并不需要一个...
  • Windows核心编程之共享内存

    千次阅读 2016-11-10 10:09:00
    Windows共享数据和信息的机制:RPC、COM、OLE、DDE、窗口消息、剪贴板、邮箱、管道、套接字以及内存映射文件。 内存映射:通过让两个或多个进程映射同一个文件。(在进程空间中保留一个地址空间区域,将物理存储器...
  • Windows进程间共享内存通信实例

    千次阅读 2015-10-23 16:51:33
    Windows进程间共享内存通信实例
  • Windows进程间通信-共享内存

    千次阅读 2014-08-21 20:31:21
    Windows进程间通信-共享内存
  • 共享内存 (也叫内存映射文件) 主要是通过映射机制实现的 , Windows 下进程的地址空间在逻辑上是相互隔离的 , 但在物理上却是重叠的 ; 所谓的重叠是指同一块内存区域可能被多个进程同时使用 , 当调用 ...
  • 公司有台服务器, 上面部署了SQLServer 与三个软件,8G内存。内存一直占用特别高接近90%,但...发现共享内存使用特别多。网上的解决方法都是说图元文件过大的。 我想请问,这个可共享内存过大如何解决?这个能释放么?

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 222,161
精华内容 88,864
关键字:

windows共享内存