【问题标题】:Can I pass a pointer using memory mapped files?我可以使用内存映射文件传递指针吗?
【发布时间】:2017-06-30 09:32:12
【问题描述】:

我已阅读有关Memory-Mapped Files 的文章和有关CreateFileMapping 的示例。
我的问题是:我可以使用内存映射文件在两个进程之间传递指向结构或对象的指针吗?


由于有一些答案是可能的,这里是我想传递的结构:
// First Process
struct OtherStruct{};

struct MyStruct
{
    unsigned long       handleObject;
    unsigned long       *phandleObject;
    OtherStruct         someData;
    OtherStruct         *pData;
}

MyStruct dataSend = { ... };
WriteToMappedFile(data);

// Second Process
MyStruct dataReceived = ReadFromMappedFile()

【问题讨论】:

  • 您必须将结构的内容memcpy 映射到内存映射文件。
  • 澄清你的问题:你想知道你是否可以通过内存映射文件(你肯定可以)传递一个指针,或者你是否能够从其他进程访问结构(只有在结构也位于内存映射区域内时才能这样做)。在这种情况下,因为每个进程都有自己的虚拟内存布局,您将不得不使用相对于内存映射文件的寻址。有关详细信息,请参阅下面的答案。
  • 感谢大家。可以举几个例子吗?
  • 我认为你需要更具体一点,你想从一个进程传递到另一个进程。您是否使用使用指针来引用不同节点的数据结构(如链表、树、图)?或者是否可以传递结构 by value 而不是传递指针?这会大大简化事情。

标签: c++ linux windows pointers ipc


【解决方案1】:

正如其他答案已经说明的那样,您必须依赖内存映射区域的地址相等,或者您必须从指针中的绝对地址移动到相对地址。

我最近偶然发现的一个可能的实现是 Boost 库中的 offset_ptr,它似乎非常适合您的用例。

【讨论】:

    【解决方案2】:

    答案取决于您想要达到的目标。在共享内存中传递指针很容易,但其他进程可能无法按照您期望的方式使用它。

    请注意,指针包含它指向的数据结构的虚拟地址。这样的虚拟地址仅在持有指向数据结构的进程内有效。如果将指针传递给另一个进程,则另一个进程将拥有自己的虚拟地址空间,传递的指针将失去其有效性。

    所以你的问题的答案是:是的,你可以传递指针,但是如果没有进一步的操作,你将无法在接收过程中成功使用这个指针。具体来说,您很可能无法使用它来访问它指向的结构或对象。

    如果要在其他进程中访问结构体或对象,则需要执行以下操作:

    • 将对象本身放入共享内存中。
    • 将指向对象的指针转换为相对于内存映射文件开头的偏移量。
    • 将此偏移量传递给其他进程
    • 在其他进程中,使用偏移量转换回指针。

    boost::offset_ptr 可以为您提供部分帮助。

    【讨论】:

    • 你能给我更多关于“将指向对象的指针转换为相对于内存映射文件开头的偏移量”的详细信息吗?我该如何实现它?
    • 更多信息请参见boost::offset_ptr 的文档。
    • 如果您想手动执行此操作,并且您正在使用 mmap() 调用将文件映射到内存,则使用 mmap() 的返回值作为基地址,从中减去映射内存区域内对象的地址,以形成偏移量。请注意,您必须将指针类型转换为 char*,因为您不能减去 void*。
    【解决方案3】:

    假设指针指向属于同一内存映射区域的结构,是的,这是有道理的。但是你必须确保内存映射区域映射到相同的虚拟地址,这并不总是得到保证,并且是一种糟糕的设计方式。

    您可以改为传递偏移量,并处理此内存区域中存在的所有 fpor 结构的相对偏移量。

    【讨论】:

    • 我会重写那句话“,这是不可能的,除非它映射到同一个内存映射区域(你通常无法控制) ...”
    • 谢谢,但我认为 No 是一个非常强的词 MapViewOfFileEx 确实需要一个基地址,我已经对实际使用该字段的代码感到不安,但是在某些情况下,自定义 shimming/hooking 方案会覆盖DLL 可以逃脱惩罚。
    【解决方案4】:

    如果你要传入内存映射文件的指针不是被 GlobalAlloc 分配的,也没有被 GlobalLock 锁住,是不行的。 但是,你已经分配了内存传递数据。所以你可以在memory-mapped-file上重写内存。

    【讨论】:

    • Globalalloc 只是从该进程的全局堆中分配,它不会指向另一个进程地址空间中的结构。
    • 自从恐龙来到地球以来,“不再”已经不再存在,您现在可以随时从洞穴中出来。 :D
    猜你喜欢
    • 2014-01-26
    • 2011-01-26
    • 2019-11-21
    • 1970-01-01
    • 1970-01-01
    • 2020-08-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多