Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/arrays/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ c++;WINAPI结构的共享内存数组_C++_Arrays_Windows_Shared Memory - Fatal编程技术网

C++ c++;WINAPI结构的共享内存数组

C++ c++;WINAPI结构的共享内存数组,c++,arrays,windows,shared-memory,C++,Arrays,Windows,Shared Memory,我正在尝试使用WINAPI通过共享命名内存共享结构数组。我能够创建和管理共享内存,但当尝试共享结构数组时,数组的大小在读取时始终为0 下面是我编写的测试代码,它应该写入/读取10个条目的数组,但即使这样也失败了。然而,我的目标是写/读一个动态结构数组,其中包含2个动态数组以及它们目前已经包含的信息 我知道我不应该在进程之间共享指针,因为它们可能指向随机值。因此,我使用new为数组分配内存 这就是我到目前为止所做的: 在两个进程中共享: #define MEMSIZE 90024 typede

我正在尝试使用WINAPI通过共享命名内存共享结构数组。我能够创建和管理共享内存,但当尝试共享结构数组时,数组的大小在读取时始终为0

下面是我编写的测试代码,它应该写入/读取10个条目的数组,但即使这样也失败了。然而,我的目标是写/读一个动态结构数组,其中包含2个动态数组以及它们目前已经包含的信息

我知道我不应该在进程之间共享指针,因为它们可能指向随机值。因此,我使用new为数组分配内存

这就是我到目前为止所做的:

在两个进程中共享:

#define MEMSIZE 90024 

typedef struct {
    int id;
    int type;
    int count;
} Entry;
extern HANDLE hMapObject;
extern void* vMapData;

std::vector<Entry> entries;//collection of entries

BOOL DumpEntries(TCHAR* memName) {//Returns true, writing 10 entries
    int size = min(10, entries.size());

    Entry* eArray = new Entry[size];
    for (int i = 0; i < size; i++) {
        eArray[i] = entries.at(i);
    }

    ::hMapObject = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, MEMSIZE, memName);
    if (::hMapObject == NULL) {
        return FALSE;
    }

    ::vMapData = MapViewOfFile(::hMapObject, FILE_MAP_ALL_ACCESS, 0, 0, MEMSIZE);
    if (::vMapData == NULL) {
        CloseHandle(::hMapObject);
        return FALSE;
    }

    CopyMemory(::vMapData, eArray, (size * sizeof(Entry)));
    UnmapViewOfFile(::vMapData);
    //delete[] eArray;
    return TRUE;
}
BOOL ReadEntries(TCHAR* memName, Entry* entries) {//Returns true reading 0 entries
    HANDLE hMapFile = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, memName);
    if (hMapFile == NULL) {
        return FALSE;
    }

    Entry* tmpEntries = (Entry*)(MapViewOfFile(hMapFile, FILE_MAP_ALL_ACCESS, 0, 0, 10 * sizeof(Entry)));
    if (tmpEntries == NULL) {
        CloseHandle(hMapFile);
        return FALSE;
    }

    entries = new Entry[10];

    for (int i = 0; i < 10; i++) {
        entries[i] = tmpEntries[i];
    }

    UnmapViewOfFile(tmpEntries);
    CloseHandle(hMapFile);
    return TRUE;
}
过程1:

#define MEMSIZE 90024 

typedef struct {
    int id;
    int type;
    int count;
} Entry;
extern HANDLE hMapObject;
extern void* vMapData;

std::vector<Entry> entries;//collection of entries

BOOL DumpEntries(TCHAR* memName) {//Returns true, writing 10 entries
    int size = min(10, entries.size());

    Entry* eArray = new Entry[size];
    for (int i = 0; i < size; i++) {
        eArray[i] = entries.at(i);
    }

    ::hMapObject = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, MEMSIZE, memName);
    if (::hMapObject == NULL) {
        return FALSE;
    }

    ::vMapData = MapViewOfFile(::hMapObject, FILE_MAP_ALL_ACCESS, 0, 0, MEMSIZE);
    if (::vMapData == NULL) {
        CloseHandle(::hMapObject);
        return FALSE;
    }

    CopyMemory(::vMapData, eArray, (size * sizeof(Entry)));
    UnmapViewOfFile(::vMapData);
    //delete[] eArray;
    return TRUE;
}
BOOL ReadEntries(TCHAR* memName, Entry* entries) {//Returns true reading 0 entries
    HANDLE hMapFile = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, memName);
    if (hMapFile == NULL) {
        return FALSE;
    }

    Entry* tmpEntries = (Entry*)(MapViewOfFile(hMapFile, FILE_MAP_ALL_ACCESS, 0, 0, 10 * sizeof(Entry)));
    if (tmpEntries == NULL) {
        CloseHandle(hMapFile);
        return FALSE;
    }

    entries = new Entry[10];

    for (int i = 0; i < 10; i++) {
        entries[i] = tmpEntries[i];
    }

    UnmapViewOfFile(tmpEntries);
    CloseHandle(hMapFile);
    return TRUE;
}

所以我的问题是,我做错了什么?我在两个进程之间共享同一个结构,为要写入的条目分配新内存,并复制大小为
10*sizeof(条目)的内存。当尝试阅读时,我也尝试阅读
10*sizeof(条目)字节并将数据强制转换为
条目*
。有什么我遗漏的吗?欢迎提供所有帮助。

基于粗略检查,此代码似乎试图将包含std::string的结构映射到共享内存中,以供其他进程使用

不幸的是,这场冒险在开始之前就注定了。即使您正确地传递了数组长度,我希望另一个进程会立即崩溃,只要它嗅到另一个进程试图映射到共享内存段的
std::string

std::string
s是非平凡类。
std::string
维护指向保存实际字符串数据的缓冲区的内部指针;在堆上分配缓冲区

您知道
sizeof(std::string)
不会改变,无论字符串包含五个字符,还是“战争与和平”的全部内容,对吗?停下来想一想,在存储
std::string
所需的几个字节内,这是怎么可能的

一旦你想一想,就会非常清楚为什么将一个进程的
std::string
s映射到一个共享内存段,然后再尝试由另一个进程获取它们是行不通的


唯一可以实际映射到共享内存或从共享内存映射到共享内存的是;虽然可以不使用聚合,但在某些情况下也是如此。

恐怕问题只存在于
\u ARRAYSIZE
宏中。我无法在MSDN中找到它,但我在其他页面中找到了
\u countof
ARRAYSIZE
的参考。所有这些都定义为
sizeof(array)/sizeof(array[0])
。问题在于,它只对定义为
条目[10]
的真正数组有意义,而对指向这样一个数组的指针则没有意义。从技术上讲,当您声明:

Entry* entries;
sizeof(entries)
是指针大小的
sizeof(Entry*)
。它小于结构的大小,因此整数除法的结果是。。。0!

无论如何,当前代码中还有其他问题。通过共享内存交换可变大小数组的正确方法是使用一个辅助结构,该结构包含一个大小,并且数组本身声明为不完整:

你可以这样扔:

BOOL DumpEntries(TCHAR* memName) {//Returns true, writing 10 entries
    int size = min(10, entries.size());

    EntryArray* eArray = (EntryArray *) malloc(sizeof(EntryArray) + size * sizeof(Entry));
    for (int i = 0; i < size; i++) {
        eArray->entries[i] = entries.at(i);
    }
    eArray->size = size;

    ::hMapObject = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, MEMSIZE, memName);
    if (::hMapObject == NULL) {
        return FALSE;
    }

    ::vMapData = MapViewOfFile(::hMapObject, FILE_MAP_ALL_ACCESS, 0, 0, MEMSIZE);
    if (::vMapData == NULL) {
        CloseHandle(::hMapObject);
        return FALSE;
    }

    CopyMemory(::vMapData, eArray, (sizeof(EntryArray) + size * sizeof(Entry)));
    UnmapViewOfFile(::vMapData);
    free(eArray);
    return TRUE;
}
size_t ReadEntries(TCHAR* memName, Entry*& entries) {//Returns the number of entries or -1 if error
    HANDLE hMapFile = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, memName);
    if (hMapFile == NULL) {
        return -1;
    }

    EntryArray* eArray = (EntryArray*)(MapViewOfFile(hMapFile, FILE_MAP_ALL_ACCESS, 0, 0, 10 * sizeof(Entry)));
    if (eArray == NULL) {
        CloseHandle(hMapFile);
        return -1;
    }

    entries = new Entry[10]; // or even entries = new Entry[eArray->size];

    for (int i = 0; i < 10; i++) { // same: i<eArray->size ...
        entries[i] = eArray->entries[i];
    }

    UnmapViewOfFile(eArray);
    CloseHandle(hMapFile);
    return eArray.size;
}

最后但并非最不重要的一点是,反斜杠
\
是字符串中的一个特殊引号字符,它必须引用自身。所以你应该写。
TEXT(“Global\\Entries”)
我对你的代码做了一些修改:

过程1:

BOOL DumpEntries(TCHAR* memName)
{
     int size = entries.size() * sizeof(Entry) + sizeof(DWORD);

     ::hMapObject = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, size, memName);
     if (::hMapObject == NULL) {
          return FALSE;
     }

     ::vMapData = MapViewOfFile(::hMapObject, FILE_MAP_ALL_ACCESS, 0, 0, size);
     if (::vMapData == NULL) {
          CloseHandle(::hMapObject);
          return FALSE;
     }

     (*(DWORD*)::vMapData) = entries.size();
     Entry* eArray = (Entry*)(((DWORD*)::vMapData) + 1);
     for(int i = entries.size() - 1; i >= 0; i--) eArray[i] = entries.at(i);

     UnmapViewOfFile(::vMapData);
     return TRUE;
}
过程2:

BOOL ReadEntries(TCHAR* memName, Entry** entries, DWORD &number_of_entries) {
     HANDLE hMapFile = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, memName);
     if (hMapFile == NULL) {
          return FALSE;
     }

     DWORD *num_entries = (DWORD*)MapViewOfFile(hMapFile, FILE_MAP_ALL_ACCESS, 0, 0, 0);
     if (num_entries == NULL) {
          CloseHandle(hMapFile);
          return FALSE;
     }
     number_of_entries = *num_entries;

     if(number_of_entries == 0)
     {
         // special case: when no entries was found in buffer
         *entries = NULL;
         return true;
     }

     Entry* tmpEntries = (Entry*)(num_entries + 1);

     *entries = new Entry[*num_entries];

     for (UINT i = 0; i < *num_entries; i++) {
          (*entries)[i] = tmpEntries[i];
     }

     UnmapViewOfFile(num_entries);
     CloseHandle(hMapFile);

     return TRUE;
}
变化:

  • 在映射内存时,我没有使用静态大小(MEMSIZE),而是精确计算所需的内存
  • 我把一个“头”放到内存映射中,一个DWORD用于发送到缓冲区中处理2个条目
  • 您的ReadEntries定义错误,我将其修复为将条目*更改为条目**
注:

  • 在进程2调用ReadEntries之前,需要关闭进程1中的::hMapObject句柄
  • 在使用进程2中为ReadEntries返回的内存项之前,需要先删除它
  • 此代码仅适用于同一windows用户,如果您想与用户进程(例如)通信服务,则需要在CreateFileMapping过程中处理SECURITY_ATTRIBUTES成员

是否将数组长度和元素存储在共享内存中?标记为.NET或其他什么,它不是标准C++,它是微软C++或只是使用POSIX套接字API。也许work@JakubKaszycki:它不是.net,但只有Winapi…_ARRAYSIZE(entries)将扩展为sizeof(entries)/sizeof(*(entries))和sizeof(entries)==0(对于您的情况),这就是为什么_ARRAYSIZE(entries)==0。您只能获取固定大小数组的大小。嘿,谢谢您的评论。我并不是真的想分享
std::string
,因为我使用的是
TCHAR*
,我只是把它作为例子添加到OP中。关于共享命名内存,我最担心的是能够真正共享
std::vector
或包含
点的数组。或者更好,能够将点(x,y)的集合从一个进程发送到另一个进程。一维整数数组也不错。更新了问题谢谢您的帮助,如何处理
条目
结构中的动态数组?我将很快对此进行测试。这看起来很有希望,稍后会尝试并让您知道。当创建
文本(“Local\\Entries”)
内存时,我应该能够在同一台计算机上的不同进程中读取内存,对吗?当试图在读取时创建本地内存时,它找不到内存并打印“未找到文件”。文本(“全局\\条目”)适用于所有进程,文本(“本地\\条目”)适用于同一用户名空间中的进程。这一点在这里得到了更好的解释:到目前为止进展顺利,但还有一个小问题。这个
void main()
{
    Entry* entries;
    DWORD number_of_entries;

    if(ReadEntries(TEXT("Global\\Entries", &entries, number_of_entries) && number_of_entries > 0)
    {
        // do something
    }
    delete entries;
}