簡體   English   中英

C ++ WINAPI共享內存動態數組

[英]C++ WINAPI Shared memory dynamic arrays

我正在嘗試使用共享內存共享包含2個動態數組的結構數組,以在另一個進程中使用這些結構。 到目前為止,我可以共享一個結構體數組,但是這些還不包含動態數組。 對解決此問題的任何幫助將是巨大的。

預期:

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項中。 您可以做的是將共享內存塊本身分配為足夠大的空間,以容納所有陣列數據,然后根據需要使用偏移量訪問各種陣列,例如:

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

另外,您應該考慮自動執行內存管理和循環,而不是手動執行所有操作:

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()共享事件同步,以便在DumpEntries()仍在寫入時, ReadEntries()不會嘗試從內存中讀取對此,反之亦然。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM