MapViewOfFile() 仅返回缓冲区中的最后一个字参见示例

问题描述

我用内存映射文件写了一个简单的进程间通信。该代码运行得相对较好,但我将在稍后解释缓冲区的问题。这是代码(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,1024,L"mmapFile");
        if (hMapFile == NULL)
        {
            std::cout << "CreateFileMapping() Error: " << GetLastError() << "\n";
            return GetLastError();
        }

        hEvent = CreateEvent(NULL,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);
        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,L"mmapFile");
        if (hMapFile == NULL)
        {
            std::cout << "CreateFileMapping() Error: " << GetLastError() << "\n";
            return GetLastError();
        }

        hEvent = OpenEvent(EVENT_ALL_ACCESS,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);
        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。如何修复缓冲区将获取整个文本的代码

解决方法

在用新数据覆盖之前,您的写入器不会等待读取器使用数据。

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

试试这个:

#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,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,BufSize);
        if (!buff)
        {
            dwError = GetLastError();
            std::cout << "MapViewOfFile() Error: " << dwError << "\n";
            SetEvent(isOpened);
            return dwError;
        }

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

        hHasDataEvent = CreateEvent(NULL,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,L"mmapFile");
        if (hMapFile == NULL)
        {
            dwError = GetLastError();
            std::cout << "CreateFileMapping() Error: " << dwError << "\n";
            return dwError;
        }

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

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

        hHasDataEvent = OpenEvent(SYNCHRONIZE,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;
}