C ++ WINAPI共享内存动态数组 [英] C++ WINAPI Shared memory dynamic arrays

查看:140
本文介绍了C ++ WINAPI共享内存动态数组的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图共享一个包含2个动态数组的结构体数组,使用共享内存在另一个过程中使用结构体。到目前为止,我可以共享一个结构体数组,但这些不包含动态数组。任何帮助完成这个问题将是巨大的。

I'm trying to share an array of structs containing 2 dynamic arrays using shared memory to use the structs in another process. So far I can share an array of structs but these do not contain dynamic arrays yet. Any help on completing this problem would be great.

预期:

typedef struct {
    int id;
    int type;
    int count;
    int[] values;
    int[] settings;
} Entry;

当前代码:

typedef struct {
    int id;
    int type;
    int count;
} Entry;

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;
}

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;
}


推荐答案

跨过进程边界,因此您不能将指针存储在放在共享内存中的 struct 项中。你可以做的是将共享内存块本身分配为足够大以容纳所有数组数据,然后使用偏移量根据需要访问各种数组,例如:

You can't pass pointers across process boundaries, so you can't store pointers inside the struct items that you put in the shared memory. What you can do is allocate the shared memory block itself to be large enough to hold all of the array data, and then use offsets to access the various arrays as needed, eg:

typedef struct
{
    int id;
    int type;
    int count;
    int *values;
    int *settings;
} Entry;

#pragma pack(push, 1)
typedef struct
{
    int id;
    int type;
    int count;
    DWORD values_offset;
    DWORD values_count; // if different than 'int count'
    DWORD settings_offset;
    DWORD settings_count; // if different than 'int count' 
} SharedMemEntry;
#pragma pack(pop)

BOOL DumpEntries(TCHAR* memName)
{
    DWORD NumValues = 0;
    DWORD NumSettings = 0;

    // or whatever your container actually is...
    for(std::vector<Entry>::reverse_iterator iter = entries.rbegin();
        iter != entries.rend(); ++iter)
    {
        Entry &e = *iter;

        // or whatever you have to do to calculate how many
        // integers are in the values[] and settings[] arrays...
        //
        NumValues += e.count;
        NumSettings += e.count;
    }

    DWORD memsize = sizeof(DWORD) +
                    (entries.size() * sizeof(SharedMemEntry)) +
                    (sizeof(int) * NumValues) +
                    (sizeof(int) * NumSettings);

    if (hMapObject != NULL)
        CloseHandle(hMapObject);

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

    BYTE *vMapData = (BYTE*) MapViewOfFile(hMapObject, FILE_MAP_WRITE, 0, 0, memsize);
    if (vMapData == NULL) {
        CloseHandle(hMapObject);
        hMapObject = NULL;
        return FALSE;
    }

    DWORD *pEntryCount = (DWORD*) vMapData;
    *pEntryCount = entries.size();

    SharedMemEntry* pEntries = (SharedMemEntry*) (pEntryCount + 1);
    int *pValues = (int*) (pEntries + entries.size());
    int *pSettings = (int*) (pValues + NumValues);

    // or whatever your container actually is...
    for(std::vector<Entry>::reverse_iterator iter = entries.rbegin();
        iter != entries.rend(); ++iter)
    {
        Entry &e = *iter;
        SharedMemEntry &eEntry = *pEntries++;

        eEntry.id = e.id;
        eEntry.type = e.type;
        eEntry.count = e.count;

        eEntry.values_offset = ((BYTE*)pValues - vMapData);
        eEntry.values_count = e.count; // or whatever you need...
        for(DWORD k = 0; k < eEntry.values_count; ++k) {
            *pValues++ = e.values[k];
        }

        eEntry.settings_offset = ((BYTE*)pSettings - vMapData);
        eEntry.settings_count = e.count; // or whatever you need...
        for(DWORD k = 0; k < eEntry.settings_count; ++k) {
            *pSettings++ = e.settings[k];
        }
    }

    UnmapViewOfFile(vMapData);
    return TRUE;
}

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

    BYTE *vMapData = (BYTE*) MapViewOfFile(hMapFile, FILE_MAP_READ, 0, 0, 0);
    if (vMapData == NULL) {
        CloseHandle(hMapFile);
        return FALSE;
    }

    DWORD *pEntryCount = (DWORD*) vMapData;
    num_entries = *pEntryCount;

    if (num_entries == 0)
    {
        // special case: when no entries was found in buffer
        *entries = NULL;
    }
    else
    {
        SharedMemEntry *pEntries = (SharedMemEntry*) (pEntryCount + 1);

        *entries = new Entry[num_entries];

        for (DWORD i = 0; i < num_entries; ++i)
        {
            Entry &e = (*entries)[i];
            SharedMemEntry &eEntry = pEntries[i];

            e.id = eEntry.id;
            e.type = eEntry.type;
            e.count = eEntry.count;

            e.values = new int[eEntry.values_count];
            e.settings = new int[eEntry.settings_count];

            int *pValues = (int*) (vMapData + eEntry.values_offset);
            for(DWORD j = 0; j < eEntry.values_count; ++j) {
                e.values[j] = pValues[j];
            }

            int *pSettings = (int*) (vMapData + eEntry.settings_offset);
            for(DWORD j = 0; j < eEntry.settings_count; ++j) {
                e.settings[j] = pSettings[j];
            }
        }
    }

    UnmapViewOfFile(vMapData);
    CloseHandle(hMapFile);

    return TRUE;
}

或者,您应该考虑自动化内存管理和循环, :

Alternatively, you should consider automating the memory management and loops instead of doing everything manually:

typedef struct
{
    int id;
    int type;
    int count;
    std::vector<int> values;
    std::vector<int> settings;
} Entry;

#pragma pack(push, 1)
typedef struct
{
    int id;
    int type;
    int count;
    DWORD values_offset;
    DWORD values_count; // if different than 'int count'
    DWORD settings_offset;
    DWORD settings_count; // if different than 'int count' 
} SharedMemEntry;
#pragma pack(pop)

BOOL DumpEntries(TCHAR* memName)
{
    DWORD NumValues = 0;
    DWORD NumSettings = 0;

    // or whatever your container actually is...
    for(std::vector<Entry>::reverse_iterator iter = entries.rbegin();
        iter != entries.rend(); ++iter)
    {
        Entry &e = *iter;
        NumValues += e.values.size();
        NumSettings += e.settings.size();
    }

    DWORD memsize = sizeof(DWORD) +
                    (entries.size() * sizeof(SharedMemEntry)) +
                    (sizeof(int) * NumValues) +
                    (sizeof(int) * NumSettings);

    if (hMapObject != NULL)
        CloseHandle(hMapObject);

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

    std::unique_ptr<void, decltype(&UnmapViewOfFile)> uMapData( MapViewOfFile(hMapObject, FILE_MAP_WRITE, 0, 0, memsize), &UnmapViewOfFile );
    BYTE *vMapData = (BYTE*) uMapData.get();
    if (!vMapData) {
        CloseHandle(hMapObject);
        hMapObject = NULL;
        return FALSE;
    }

    DWORD *pEntryCount = (DWORD*) vMapData;
    *pEntryCount = entries.size();

    SharedMemEntry* pEntries = (SharedMemEntry*) (pEntryCount + 1);
    int *pValues = (int*) (pEntries + entries.size());
    int *pSettings = (int*) (pValues + NumValues);

    // or whatever your container actually is...
    for(std::vector<Entry>::reverse_iterator iter = entries.rbegin();
        iter != entries.rend(); ++iter)
    {
        Entry &e = *iter;
        SharedMemEntry &eEntry = *pEntries++;

        eEntry.id = e.id;
        eEntry.type = e.type;
        eEntry.count = e.count;

        eEntry.values_offset = ((BYTE*)pValues - vMapData);
        eEntry.values_count = e.values.size();
        pValues = std::copy(e.values.begin(), e.values.end(), pValues);

        eEntry.settings_offset = ((BYTE*)pSettings - vMapData);
        eEntry.settings_count = e.settings.size();
        pSettings = std::copy(e.settings.begin(), e.settings.end(), pSettings);
    }

    return TRUE;
}

// or whatever container type you want...
BOOL ReadEntries(TCHAR* memName, std::vector<Entry> &entries)
{
    entries.clear();

    std::unique_ptr<std::remove_pointer<HANDLE>::type, decltype(&CloseHandle)> uMapFile( OpenFileMapping(FILE_MAP_READ, FALSE, memName), &CloseHandle );
    HANDLE hMapFile = uMapFile.get();
    if (!hMapFile) {
        return FALSE;
    }

    std::unique_ptr<void, decltype(&UnmapViewOfFile)> uMapData( MapViewOfFile(hMapFile, FILE_MAP_READ, 0, 0, 0), &UnmapViewOfFile );
    BYTE *vMapData = (BYTE*) uMapData.get();
    if (!vMapData) {
        return FALSE;
    }

    DWORD *pEntryCount = (DWORD*) vMapData;
    DWORD num_entries = *pEntryCount;

    if (num_entries != 0)
    {
        entries.resize(num_entries);

        SharedMemEntry *pEntries = (SharedMemEntry*) (pEntryCount + 1);

        for (DWORD i = 0; i < num_entries; ++i)
        {
            Entry &e = entries[i];
            SharedMemEntry &eEntry = pEntries[i];

            e.id = eEntry.id;
            e.type = eEntry.type;
            e.count = eEntry.count;

            e.values.reserve(eEntry.values_count);
            e.settings.reserve(eEntry.settings_count);

            int *pValues = (int*) (vMapData + eEntry.values_offset);
            std::copy(pValues, pValues + eEntry.values_count, std::back_inserter(e.values));

            int *pSettings = (int*) (vMapData + eEntry.settings_offset);
            std::copy(pSettings, pSettings + eEntry.settings_count, std::back_inserter(e.settings));
        }
    }

    return TRUE;
}

无论哪种方式,请确保在 DumpEntries() ReadEntries(),例如 CreateEvent c>,所以 ReadEntries()不会尝试从内存中读取 DumpEntries()它,反之亦然。

Either way, make sure you provide some kind of synchronization between DumpEntries() and ReadEntries(), such as with shared events from CreateEvent(), so that ReadEntries() does not try to read from the memory while DumpEntries() is still writing to it, and vice versa.

这篇关于C ++ WINAPI共享内存动态数组的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆