共享内存主要是通过映射机制实现的。
Windows 下进程的地址空间在逻辑上是相互隔离的,但在物理上却是重叠的。所谓的重叠是指同一块内存区域可能被多个进程同时使用。系统把同一块内存区域映射到了不同进程的地址空间中,从而达到共享内存的目的。
示例代码中,一方是QT编写的程序来创建并读取共享内存的内容,另一方是VC程序修改共享内存中的内容:
QT:
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>
#include <iostream>
#include <Windows.h>
#include <windef.h>
using namespace std;
struct MapStruct
{
char data[1024];
};
HANDLE hMap;
MapStruct* pBuffer;
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
string strMapData("Hello world");
// 创建一个命名的内存映射文件对象
hMap = ::CreateFileMapping(INVALID_HANDLE_VALUE,
NULL,
PAGE_READWRITE,
0,
sizeof (MapStruct),
L"Test");
// 映射对象的一个视图,得到指向共享内存的指针,设置里面的数据
pBuffer = (MapStruct*)::MapViewOfFile(hMap, FILE_MAP_ALL_ACCESS, 0, 0, 0);
if(pBuffer)
{
memset(pBuffer, 0, sizeof(pBuffer));
}
else
{
qDebug()<<"fail";
CloseHandle(hMap);
return;
}
strcpy(pBuffer->data,strMapData.c_str());
}
MainWindow::~MainWindow()
{
// 解除文件映射,关闭内存映射文件对象句柄
::UnmapViewOfFile(pBuffer);
::CloseHandle(hMap);
delete ui;
}
VC:
#include <iostream>
#include <Windows.h>
#include <string>
using namespace std;
struct MapStruct
{
char data[1024];
};
int main()
{
std::cout << "Hello ShareMemory!/n"<<std::endl;
string strMapData("Hello world");
HANDLE hMap = ::OpenFileMapping(FILE_MAP_ALL_ACCESS, 0, L"Test");
if(NULL==hMap)
{
std::cout << "No ShareMemory!/n" << std::endl;
}
else
{
MapStruct* myBuffer = (MapStruct*)::MapViewOfFile(hMap,FILE_MAP_ALL_ACCESS,0,0,0);
std::cout << myBuffer->data<<std::endl;
}
}
下一步,添加一个线程来循环处理这个数据
QT:
void MyThread::run()
{
while(threadRun)
{
sleep(1);
std::cout << pBuffer->data<<std::endl;
}
}
多个进程在这一处内存读写数据,肯定要通过同步互斥的手段来控制进程读取的顺序,避免同时对数据读写
这里采用内核事件,可以用于进程同步
QT:
//创建一个事件
bEventHandler=CreateEvent(NULL,FALSE,FALSE,L"myevent");
while(threadRun)
{
//等待读取事件
WaitForSingleObject(bEventHandler,INFINITE);
std::cout << pBuffer->data<<std::endl;
}
VC:
bEventHandler = OpenEvent(EVENT_ALL_ACCESS, FALSE, L"myevent");//获取事件句柄
MapStruct* myBuffer = (MapStruct*)::MapViewOfFile(hMap,FILE_MAP_ALL_ACCESS,0,0,0);
std::cout << myBuffer->data<<std::endl;
memcpy(myBuffer->data,"1agag567",20);
SetEvent(bEventHandler);//发送事件
QT程序启动后,创建共享内存,创建事件并等待事件到来。
VC启动后,打开共享内存,修改共享内存的内容,设置事件。
QT等到事件,打印共享内存中的内容。