使用命名共享内存的C ++问题

时间:2017-10-30 18:25:38

标签: c++ winapi memory

我试图实现共享内存接口,但是我无法让它工作。

由于它还没有工作,我想请求帮助。 我的应用程序需要共享内存,这是一个在多个进程上运行的多目标进化算法,但是各种进程需要交换信息,而不是将其转储到物理文件中十亿次,我宁愿共享内存使用这种方法。

我在VS v120中使用C ++在Win7x64上。 为了测试,所有这些代码都在同一个过程中进行,直到我发现它为止。

我的文件名是一个常量字符串

 m_Filename = "Local\\shared_memory"

 m_BufferSize = 1024

编辑1:

所以我看到我在这里要做的事情有些混乱,我也很困惑。 查看MSDN的官方文档,它使用 INVALID_HANDLE_VALUE 的文件映射,他们似乎不在磁盘上创建文件。 这对我的解决方案很好。我不需要磁盘上的文件,尽管两者都有效。 我试图以另一种方式做到这一点的原因是因为第一种方法失败了,我开始搜索,我遇到了这里的线程,人们说他们也需要制作实际的文件。

这是一个更完整的代码,是的,我确实检查了错误代码。

m_Filename在类构造函数中设置。缓冲区大小是不变的。 我已经删除了执行物理文件的代码,我猜它实际上并不需要吗?

    void MemoryMapper::_CreateMappedFile() {

    m_Handle = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE,
        0, m_BufferSize, m_Filename.c_str());

    if (m_Handle == NULL)
    {
        std::cout << m_DebugErrorTitle << "_CreateMappedFile(): " << MM_ERROR_CREATE_FAILED << 
            " (" << GetLastError() << ")" << std::endl;
        return;
    }

    m_pBuffer = (LPTSTR)MapViewOfFile(m_Handle, FILE_MAP_ALL_ACCESS, 0, 0, m_BufferSize);

    if (m_pBuffer == NULL)
    {
        std::cout << m_DebugErrorTitle << "_CreateMappedFile(): " << MM_ERROR_MAPPING_FAILED << 
            " (" << GetLastError() << ")" << std::endl;
        CloseHandle(m_Handle);
        return;
    }

    TCHAR szMsg[] = TEXT("Test message.");
    CopyMemory((PVOID)m_pBuffer, szMsg, (_tcslen(szMsg) * sizeof(TCHAR)));

    if (!UnmapViewOfFile(m_pBuffer)) {
        std::cout << m_DebugErrorTitle << "_CreateMappedFile(): UnmapViewOfFile() returned false. (" << GetLastError() << ")" << std::endl;
    }
    if (!CloseHandle(m_Handle)) {
        std::cout << m_DebugErrorTitle << "_CreateMappedFile(): CloseHandle() returned false. (" << GetLastError() << ")" << std::endl;
    }

    if (m_Debug > 1) { std::cout << m_DebugTitle << "Created mapped file: '" << m_Filename << "'." << std::endl; }
}

运行此代码,我最终得到了控制台消息: [MemoryMapper]创建映射文件:&#39; Local \ shared_memory&#39;。

然后,在同一过程中,为了测试?我尝试再次打开该文件。 这次我收到错误代码2,说该文件不存在。

bool MemoryMapper::_Open(const std::string& fn) {

    if (m_Debug > 2) { std::cout << m_DebugTitle << "Open '" << fn << "'." << std::endl; }

    m_OpenHandle = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, fn.c_str());

    if (m_OpenHandle == NULL)
    {
        std::cout << m_DebugErrorTitle << " _Open('" << fn << "'): " << MM_ERROR_OPEN_FAILED << " (" << GetLastError() << ")" << std::endl;
        m_IsOpen = false;
        return m_IsOpen;
    }
    m_IsOpen = true;
    if (m_Debug > 1) { std::cout << m_DebugTitle << "Open: " << std::to_string(m_IsOpen) << std::endl; }
    return m_IsOpen;
}

文件名是相同的。 100%。

为什么我无法打开文件?

另外,在创建文件名之前,我是否应该检查共享内存对象是否存在set filename?当应用程序终止时,对象是否被清除?

编辑2:

似乎初始CreateFileMapping()给出的句柄必须在我想要使用共享对象的持续时间内保持打开状态?

我尝试了这个,现在似乎工作正常。 我可以使用单独的调用来创建对象,打开它,写入和关闭它。 我的错误是在创建时关闭句柄,尽管这是正确的吗?

1 个答案:

答案 0 :(得分:1)

首先,如果您尝试实现共享内存接口 - 为您在磁盘上创建文件?你可以这样做,但在这种情况下绝对不需要

  

(3)现在对象本身应该存在于内存中,不是吗?

现在对象确实存在于NT命名空间中,但直到你没有关闭它的最后一个句柄。当最后一个句柄关闭时,对象名称将从NT命名空间中删除,除非你在OBJECT_ATTRIBUTES中没有使用OBJ_PERMANENT标志。但是,对于此需求,请使用NtCreateSection代替CreateFileMapping并使用SE_CREATE_PERMANENT_PRIVILEGE

如果OpenFileMapping失败并显示错误ERROR_FILE_NOT_FOUND,则表示您在调用中使用的名称不存在于NT命名空间中。这可能有以下几个原因: - 如果您从会话中运行,则在另一个终端会话(OpenFileMapping下运行的Local\shared_memory调用的流程会扩展为\Sessions\<SessionId>\BaseNamedObjects\shared_memory\BaseNamedObjects\shared_memory 0)。你可以简单地误认为名字。

但速度更快 - 关闭部分句柄,在CreateFileMapping之前由OpenFileMapping返回。因为当关闭它们的所有打开句柄时,不会删除OBJ_PERMANENT对象名称。如果存在对它的引用,对象本身可以继续存在 - 例如当你调用MapViewOfFile时 - 你创建对section的引用 - 并且在你不取消它之前它将不被删除,但是当所有打开时,部分名称将被删除它们的把手是关闭的。

我在开始时如何假设 - OpenFileMapping失败,因为它所调用的部分不再存在。它处理已经关闭。事实上void MemoryMapper::_CreateMappedFile()什么都不做 - 这个函数创建临时对象,用它做一些操作并在退出时销毁。所有这些在函数返回后都没有任何影响