【Windows进程通信】共享内存

本文探讨了Windows下如何通过映射机制实现共享内存,以QT和VC程序为例,展示了创建、读写共享内存以及使用内核事件进行进程同步的过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

共享内存主要是通过映射机制实现的。
  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等到事件,打印共享内存中的内容。

以下是一个使用共享内存进行进程间通信的客户端和服务端的示例代码,代码中包括了创建和映射共享内存,以及读写共享内存的基本操作。 服务端代码: ``` #include <windows.h> #include <stdio.h> int main() { HANDLE hMapFile; LPCTSTR pBuf; // 创建共享内存 hMapFile = CreateFileMapping( INVALID_HANDLE_VALUE, // 使用无效的句柄 NULL, // 默认安全级别 PAGE_READWRITE, // 可读写 0, // 高位字节数 1024, // 低位字节数 TEXT("MyFileMappingObject")); // 共享内存名称 if (hMapFile == NULL) { printf("CreateFileMapping failed (%d)\n", GetLastError()); return 1; } // 映射共享内存 pBuf = (LPTSTR)MapViewOfFile( hMapFile, // 共享内存句柄 FILE_MAP_ALL_ACCESS,// 可读写 0, 0, 1024); if (pBuf == NULL) { printf("MapViewOfFile failed (%d)\n", GetLastError()); CloseHandle(hMapFile); return 1; } // 从共享内存中读取数据 printf("Buf: %s\n", pBuf); // 写入数据到共享内存 CopyMemory((LPVOID)pBuf, "Hello from server!", sizeof("Hello from server!")); // 解除映射 UnmapViewOfFile(pBuf); // 关闭句柄 CloseHandle(hMapFile); return 0; } ``` 客户端代码: ``` #include <windows.h> #include <stdio.h> int main() { HANDLE hMapFile; LPCTSTR pBuf; // 打开共享内存 hMapFile = OpenFileMapping( FILE_MAP_ALL_ACCESS, // 可读写 FALSE, // 不继承 TEXT("MyFileMappingObject")); // 共享内存名称 if (hMapFile == NULL) { printf("OpenFileMapping failed (%d)\n", GetLastError()); return 1; } // 映射共享内存 pBuf = (LPTSTR)MapViewOfFile( hMapFile, // 共享内存句柄 FILE_MAP_ALL_ACCESS,// 可读写 0, 0, 1024); if (pBuf == NULL) { printf("MapViewOfFile failed (%d)\n", GetLastError()); CloseHandle(hMapFile); return 1; } // 写入数据到共享内存 CopyMemory((LPVOID)pBuf, "Hello from client!", sizeof("Hello from client!")); // 从共享内存中读取数据 printf("Buf: %s\n", pBuf); // 解除映射 UnmapViewOfFile(pBuf); // 关闭句柄 CloseHandle(hMapFile); return 0; } ``` 此代码演示了如何创建一个共享内存对象,并分别在服务端和客户端中映射到进程地址空间中,然后进行数据读写。在实际应用中,需要根据具体需求进行修改和扩展。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值