【问题标题】:the shared mapped memory between two processes in't updated when it's edited两个进程之间的共享映射内存在编辑时没有更新
【发布时间】:2019-07-19 06:17:35
【问题描述】:

我在 windows 上使用 c++ 并制作了一个简单的方法来在两个进程之间进行通信

第一个进程创建映射内存,在其中写入第一条消息并为另一个进程复制句柄(映射内存未命名) 代码是这样的:

hMapped = CreateFileMappingA(INVALID_HANDLE_VALUE, 0, PAGE_READWRITE, 0, 1000, "my_shared_memory");
if (!hMapped)
{
    cout << "[!] failed to create the shared mapped memory with error : " << GetLastError() << endl;
    getchar();
}
char *shared_buffer = (char*)MapViewOfFile(hMapped, FILE_MAP_ALL_ACCESS, 0, 0, mapped_memory_size);

然后其他进程获取句柄,打开视图并检索写入的第一个缓冲区

然后它会循环并每 6 秒检查一次新的写入操作并进行处理

我从第一个过程写成这样:

std::lock_guard<std::mutex> lock(mtx);
RtlSecureZeroMemory(shared_buffer, mapped_memory_size);
shared_buffer[0] = 'n'; // it's a hint for the other process
memcpy(shared_buffer + 1, this->stuff.get_data().c_str(), this->stuff.get_data().size() + 1);

但是缓冲区没有为第二个进程更新它是第一个缓冲区

这是第二个过程中的代码:

HANDLE shared_memory = OpenFileMappingA(FILE_MAP_ALL_ACCESS, FALSE, "my_shared_memory");
char *shared_buffer = (char*)MapViewOfFile(shared_memory, FILE_MAP_ALL_ACCESS, 0, 0, 1000);

utils::command_line_parser cmd_parser;
cmd_parser.parse(std::string((char*)shared_buffer + 1));
if (!cmd_parser.valid()) { // I get that they are valid and I verify that
    printf("failed to parse the arguments !");
    return TRUE;
}
while(true)
{
    Sleep(6000);
    // CloseHandle(shared_memory);
    // shared_memory = OpenFileMappingA(FILE_MAP_ALL_ACCESS, FALSE, "my_shared_memory");
    // shared_buffer = (char*)MapViewOfFile(shared_memory, FILE_MAP_ALL_ACCESS, 0, 0, 1000);
    MessageBoxA(0, (char*)shared_buffer, "message", 0);
    char res = shared_buffer[0];
    switch (res)
    {
    case 'q' :
        // do some stuff
    case 'n' :
        // do some stuff
        break;
    default:
        break;
    }

【问题讨论】:

标签: c++ winapi ipc memory-mapped-files


【解决方案1】:

这是一个命名共享内存应用程序的示例,它似乎可以与 Visual Studio 2015 一起使用。根据指定的命令行参数,该应用程序可以作为内存区域的写入器或内存区域的读取器运行。

查看 Microsoft 的文档,似乎共享句柄需要进程分叉。 CreateFileMappingA function 以及您的原始帖子和问题,这似乎不是您在做什么。

多个进程可以共享同一文件的视图,方法是使用 单个共享文件映射对象或创建单独的文件映射 由同一文件支持的对象。单个文件映射对象可以是 通过继承进程的句柄由多个进程共享 创建、复制句柄或打开文件映射对象 按名字。有关详细信息,请参阅 CreateProcess、DuplicateHandle 和 OpenFileMapping 函数。

在以下使用命名共享内存区域的示例中,我从 CreateFileMapping, MapViewOfFile, handle leaking c++ 中示例的源代码开始,但是我只是制作了一个源文件,Windows 控制台应用程序,我可以作为两个不同的启动具有不同行为的进程。

用于以两种不同方式执行的源代码文件:

#include "stdafx.h"

#include <conio.h>
#include <iostream>

#define BUF_SIZE 256
TCHAR szName[] = TEXT("MyFileMappingObject");

int main(int argc, char **argv)
{
    HANDLE hMapFile;
    LPCTSTR pBuf;
    int     iInstance = 0;
    TCHAR szMsgFmt[] = TEXT("Message from first process %d.");

    if (argc > 1) {
        iInstance = atoi(argv[1]);
    }
    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

    DWORD lastError = GetLastError();
    if (hMapFile == NULL)
    {
        _tprintf(TEXT("Could not create file mapping object (%d).\n"),
            GetLastError());
        std::cin.get();
        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);

        std::cin.get();
        return 1;
    }


    for (int i = 1; i < 4; i++) {
        if (iInstance > 0) {
            MessageBox(NULL, pBuf, TEXT("Process2"), MB_OK);
        }
        else {
            TCHAR szMsg[128] = { 0 };
            wsprintf (szMsg, szMsgFmt, i);
            std::cout << "Copying text into shared memory " << i << std::endl;
            CopyMemory((PVOID)pBuf, szMsg, (_tcslen(szMsg) * sizeof(TCHAR)));
            std::cout << "Waiting " << std::endl;
            _getch();
        }
    }
    CloseHandle(hMapFile);


    UnmapViewOfFile(pBuf);
    return 0;
}

批处理文件 1 和批处理文件 2 作为两个不同的进程运行相同的可执行文件。

shared_mem

pause

shared_mem  1

pause

以及修改后的 stdafx.h 包含文件。

// stdafx.h : include file for standard system include files,
// or project specific include files that are used frequently, but
// are changed infrequently
//

#pragma once

#include "targetver.h"

#include <Windows.h>
#include <WinUser.h>
#include <stdio.h>
#include <tchar.h>



// TODO: reference additional headers your program requires here

编译应用程序源文件,然后运行第一个 bat 文件,该文件将启动并将一些文本放入共享内存区域,然后等待。接下来运行第二个 bat 文件,它将从共享内存区域读取文本。

我看到的是,如果您从第二个 bat 文件中单击显示对话框上的 Ok 按钮,您将再次看到相同的消息。

但是,如果您随后转到第一个 bat 文件的窗口并按 Enter 键生成下一条消息,然后返回到第二个 bat 文件生成的对话框,您将看到它将读取更新的字符串。

这都是使用一个命名的共享文件。没有尝试使用共享内存句柄。

【讨论】:

    猜你喜欢
    • 2023-03-19
    • 1970-01-01
    • 2010-11-15
    • 1970-01-01
    • 2018-07-06
    • 2014-09-02
    • 1970-01-01
    • 2013-07-16
    • 2018-10-08
    相关资源
    最近更新 更多