MapViewOfFile() Returns 只有缓冲区中的最后一个字(参见示例)

MapViewOfFile() Returns only the Last Word in the Buffer (See the Example)

我用内存映射文件写了一个简单的进程间通信。该代码运行得相对较好,但我很快就会解释缓冲区的问题。这是代码(C++,Windows):

#define UNICODE
#define _UNICODE

#include <iostream>
#include <tchar.h>
#include <Windows.h>

int wmain(int argc, wchar_t** argv)
{
    if (argc != 2)
    {
        std::cout << "Usage: `win32mmap w` for writing, or `win32mmap r` for reading.\n";
        return -1;
    }

    HANDLE hMapFile;
    HANDLE hEvent;
    HANDLE isOpened = CreateEvent(NULL, true, false, L"IsOpened"); // To check if a `win32mmap w` runs

    if (wcscmp(argv[1], L"w") == 0)
    {
        SetEvent(isOpened);

        hMapFile = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, 1024, L"mmapFile");
        if (hMapFile == NULL)
        {
            std::cout << "CreateFileMapping() Error: " << GetLastError() << "\n";
            return GetLastError();
        }

        hEvent = CreateEvent(NULL, true, false, L"mmapEvent");
        if (hEvent == INVALID_HANDLE_VALUE || hEvent == NULL)
        {
            std::cout << "CreateEvent() Error: " << GetLastError() << "\n";
            return GetLastError();
        }

        char* buff = (char*)MapViewOfFile(hMapFile, FILE_MAP_WRITE, 0, 0, 0);
        if (!buff)
        {
            std::cout << "MapViewOfFile() Error: " << GetLastError() << "\n";
            return GetLastError();
        }

        while (buff[0] != L'.')
        {
            std::cin >> buff;
            SetEvent(hEvent);
        }

        UnmapViewOfFile(buff);
    }

    else if (wcscmp(argv[1], L"r") == 0)
    {
        if (WaitForSingleObject(isOpened, 0) == WAIT_TIMEOUT)
        {
            std::cout << "Waiting for `win32mmap w`...";
            WaitForSingleObject(isOpened, INFINITE);
            std::cout << "\n";
        }

        hMapFile = OpenFileMapping(FILE_MAP_ALL_ACCESS, false, L"mmapFile");
        if (hMapFile == NULL)
        {
            std::cout << "CreateFileMapping() Error: " << GetLastError() << "\n";
            return GetLastError();
        }

        hEvent = OpenEvent(EVENT_ALL_ACCESS, false, L"mmapEvent");
        if (hEvent == INVALID_HANDLE_VALUE || hEvent == NULL)
        {
            std::cout << "CreateFile() Error: " << GetLastError() << "\n";
            return GetLastError();
        }

        char* buff = (char*)MapViewOfFile(hMapFile, FILE_MAP_READ, 0, 0, 0);
        if (!buff)
        {
            std::cout << "MapViewOfFile() Error: " << GetLastError() << "\n";
            return GetLastError();
        }

        if (!buff)
        {
            std::cout << "MapViewOfFile() Error: " << GetLastError() << "\n";
            return GetLastError();
        }

        while (true)
        {
            WaitForSingleObject(hEvent, INFINITE);
            ResetEvent(hEvent);

            if (buff[0] == '.')
            {
                break;
            }

            std::cout << buff << "\n";
        }

        UnmapViewOfFile(buff);
    }

    else
    {
        std::cout << "Usage: `win32mmap w` for writing, or `win32mmap r` for reading.\n";
        return -1;
    }

    CloseHandle(hMapFile);

    return 0;
}

该程序是一个简单的进程间通信“聊天”,它依赖于内存映射文件。要使用该程序,您需要创建该程序的两个可执行实例:win32mmap wwin32mmap r。第一个实例用于键入在第二个实例中显示的文本。当您在第一个实例中键入 . 时,它们都将终止。

我的问题是当我 运行 程序的 2 个实例时,我在第一个实例中键入世界 Hello (win32mmap w),第二个实例显示 Hello 正如预期的那样。但是当我在第一个实例中键入 Hello World 时,第二个实例只显示单词 World 而不是 Hello World。如何修复缓冲区将获取整个文本的代码?

您的编写器没有等待 reader 在用新数据覆盖数据之前使用数据。

您需要 2 个事件 - 一个用于 reader 在缓冲区有数据要读取时等待信号,一个用于写入器在缓冲区需要数据时等待信号。

试试这个:

#define UNICODE
#define _UNICODE

#include <iostream>
#include <tchar.h>
#include <Windows.h>

const DWORD BufSize = 1024;

int wmain(int argc, wchar_t** argv)
{
    if (argc != 2)
    {
        std::cout << "Usage: `win32mmap w` for writing, or `win32mmap r` for reading.\n";
        return -1;
    }

    HANDLE hMapFile;
    char* buff;

    HANDLE hNeedDataEvent;
    HANDLE hHasDataEvent;
    DWORD dwError;

    HANDLE isOpened = CreateEvent(NULL, TRUE, FALSE, L"IsOpened"); // To check if a `win32mmap w` runs
    if (isOpened == NULL)
    {
        dwError = GetLastError();
        std::cout << "CreateEvent() Error: " << dwError << "\n";
        return dwError;
    }

    if (wcscmp(argv[1], L"w") == 0)
    {
        hMapFile = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, BufSize, L"mmapFile");
        if (hMapFile == NULL)
        {
            dwError = GetLastError();
            std::cout << "CreateFileMapping() Error: " << dwError << "\n";
            SetEvent(isOpened);
            return dwError;
        }

        buff = (char*) MapViewOfFile(hMapFile, FILE_MAP_WRITE, 0, 0, BufSize);
        if (!buff)
        {
            dwError = GetLastError();
            std::cout << "MapViewOfFile() Error: " << dwError << "\n";
            SetEvent(isOpened);
            return dwError;
        }

        hNeedDataEvent = CreateEvent(NULL, TRUE, TRUE, L"mmapNeedDataEvent");
        if (hNeedDataEvent == NULL)
        {
            dwError = GetLastError();
            std::cout << "CreateEvent() Error: " << dwError << "\n";
            SetEvent(isOpened);
            return dwError;
        }

        hHasDataEvent = CreateEvent(NULL, TRUE, FALSE, L"mmapHasDataEvent");
        if (hHasDataEvent == NULL)
        {
            dwError = GetLastError();
            std::cout << "CreateEvent() Error: " << dwError << "\n";
            SetEvent(isOpened);
            return dwError;
        }

        SetEvent(isOpened);

        while (WaitForSingleObject(hNeedDataEvent, INFINITE) == WAIT_OBJECT_0)
        {
            std::cin.get(buff, BufSize);

            ResetEvent(hNeedDataEvent);
            SetEvent(hHasDataEvent);

            if (buff[0] == L'.') break;
        }
    }

    else if (wcscmp(argv[1], L"r") == 0)
    {
        if (WaitForSingleObject(isOpened, 0) == WAIT_TIMEOUT)
        {
            std::cout << "Waiting for `win32mmap w`...";
            WaitForSingleObject(isOpened, INFINITE);
            std::cout << "\n";
        }

        hMapFile = OpenFileMapping(FILE_MAP_READ, FALSE, L"mmapFile");
        if (hMapFile == NULL)
        {
            dwError = GetLastError();
            std::cout << "CreateFileMapping() Error: " << dwError << "\n";
            return dwError;
        }

        char* buff = (char*) MapViewOfFile(hMapFile, FILE_MAP_READ, 0, 0, BufSize);
        if (!buff)
        {
            dwError = GetLastError();
            std::cout << "MapViewOfFile() Error: " << dwError << "\n";
            return dwError;
        }

        hNeedDataEvent = OpenEvent(SYNCHRONIZE, FALSE, L"mmapNeedDataEvent");
        if (hNeedDataEvent == NULL)
        {
            dwError = GetLastError();
            std::cout << "OpenEvent() Error: " << dwError << "\n";
            return dwError;
        }

        hHasDataEvent = OpenEvent(SYNCHRONIZE, FALSE, L"mmapHasDataEvent");
        if (hHasDataEvent == NULL)
        {
            dwError = GetLastError();
            std::cout << "OpenEvent() Error: " << dwError << "\n";
            return dwError;
        }

        do
        {
            SetEvent(hNeedDataEvent);

            if (WaitForSingleObject(hHasDataEvent, INFINITE) != WAIT_OBJECT_0)
                break;

            std::cout << buff << "\n";

            ResetEvent(hHasDataEvent);
        }
        while (buff[0] != '.');
    }

    else
    {
        std::cout << "Usage: `win32mmap w` for writing, or `win32mmap r` for reading.\n";
        return -1;
    }

    UnmapViewOfFile(buff);
    CloseHandle(hMapFile);
    CloseHandle(hNeedDataEvent);
    CloseHandle(hHasDataEvent);
    CloseHandle(isOpened);

    return 0;
}