I. questions:
There are some problems left in the last article. This time, we mainly solve the following two problems:
1. When writing data to shared memory, it is not sure whether the data in shared memory has been processed
2. When the sending data size is larger than the shared memory size, there will be data loss
II. Implementation mode:
1. Add a read event. If the data in shared memory is adjusted by consumption, send the event
2. Increase the length of the sent data. When the total length of the read data is equal to the length of the sent data, call the data processing function
Three, code
ShareMemory.h
#ifndef SHAREMEMORY_H #define SHAREMEMORY_H #include <string> #include <list> #include <thread> #include <memory> #include "Windows.h" class ShareMemory { public: ShareMemory(std::wstring strKey, unsigned int nSize = 1024); ~ShareMemory(); void registeReceiver(std::function<void(unsigned char *, int)> pfunReceiver); void writeData(char *data, unsigned int nLength); private: void readData(); void int2Bytes(int nValue, int nLength, unsigned char* pResult); int bytes2Int(unsigned char* pData, int nLength); private: std::shared_ptr<std::thread> m_ptrReadThread; bool m_bThreadRunning = true; HANDLE m_hMapFile = nullptr; LPVOID m_buffer = nullptr; unsigned int m_nBufferSize; std::function<void(unsigned char *, int nLength)> m_pfunReceiver = nullptr; std::wstring m_strUniqueId; HANDLE m_writeEvent = nullptr; HANDLE m_readEvent = nullptr; }; #endif
ShareMemory.cpp
#include "stdafx.h" #include "ShareMemory.h" #include <iostream> ShareMemory::ShareMemory(std::wstring strKey, unsigned int nSize) : m_nBufferSize(nSize) { m_strUniqueId = std::move(strKey); m_hMapFile = OpenFileMapping(FILE_MAP_ALL_ACCESS, 0, m_strUniqueId.c_str()); if (!m_hMapFile) { m_hMapFile = CreateFileMapping(INVALID_HANDLE_VALUE, nullptr, PAGE_READWRITE, 0, m_nBufferSize, m_strUniqueId.c_str()); } if (m_hMapFile) { m_buffer = MapViewOfFile(m_hMapFile, FILE_MAP_ALL_ACCESS, 0, 0, m_nBufferSize); if (!m_buffer) { CloseHandle(m_hMapFile); } else { std::wstring strWriteKey = m_strUniqueId; strWriteKey.append(L"_write"); m_writeEvent = CreateEvent(NULL, TRUE, FALSE, strWriteKey.c_str()); std::wstring strReadKey = m_strUniqueId; strReadKey.append(L"_read"); m_readEvent = CreateEvent(NULL, TRUE, FALSE, strReadKey.c_str()); if (m_readEvent) { SetEvent(m_readEvent); } memset(m_buffer, 0, m_nBufferSize); m_ptrReadThread = std::make_shared<std::thread>(std::bind(&ShareMemory::readData, this)); } } } ShareMemory::~ShareMemory() { if (m_buffer) { UnmapViewOfFile(m_buffer); m_buffer = nullptr; } if (m_hMapFile) { CloseHandle(m_hMapFile); m_hMapFile = nullptr; } if (m_writeEvent) { CloseHandle(m_writeEvent); m_writeEvent = nullptr; } if (m_readEvent) { CloseHandle(m_readEvent); m_readEvent = nullptr; } } void ShareMemory::registeReceiver(std::function<void(unsigned char *, int)> pfunReceiver) { m_pfunReceiver = pfunReceiver; } void ShareMemory::writeData(char *data, unsigned int nLength) { if (!m_writeEvent || !m_readEvent) { return; } unsigned char *sendData = (unsigned char *)malloc(4 + nLength); if (!sendData) { //Memory request failed return; } char lenHead[4] = { 0 }; int2Bytes(nLength, 4, sendData); memcpy(sendData + 4, data, nLength); nLength += 4; int nAlreadySendSize = 0; while (nLength > 0) { DWORD dwWaitResult = WaitForSingleObject(m_readEvent, INFINITE); switch (dwWaitResult) { // Event object was signaled case WAIT_OBJECT_0: { unsigned int nSendSize = nLength < m_nBufferSize ? nLength : m_nBufferSize; memcpy(m_buffer, sendData + nAlreadySendSize, nSendSize); nAlreadySendSize += nSendSize; nLength -= nSendSize; ResetEvent(m_readEvent); SetEvent(m_writeEvent); break; } } } //Free memory delete sendData; sendData = nullptr; } void ShareMemory::readData() { if (!m_writeEvent || !m_readEvent) { return; } unsigned int nReveiceLen = 0; unsigned int nSendLen = 0; unsigned char *dataBegin = nullptr; while (m_bThreadRunning) { DWORD dwWaitResult = WaitForSingleObject(m_writeEvent, INFINITE); switch (dwWaitResult) { // Event object was signaled case WAIT_OBJECT_0: { if (m_pfunReceiver) { unsigned char *data = (unsigned char*)m_buffer; if (nSendLen == 0) { nSendLen = bytes2Int(data, 4); nReveiceLen = nSendLen > m_nBufferSize - 4 ? m_nBufferSize - 4 : nSendLen; dataBegin = (unsigned char*)malloc(nSendLen + 1); memset(dataBegin, 0, nSendLen + 1); memcpy(dataBegin, data + 4, nReveiceLen); memset(m_buffer, 0, nReveiceLen + 4); } else { int nLen = nReveiceLen + m_nBufferSize > nSendLen ? (nSendLen - nReveiceLen) : m_nBufferSize; memcpy(dataBegin + nReveiceLen * sizeof(unsigned char), data, nLen); nReveiceLen += nLen; memset(m_buffer, 0, nLen); } if (nReveiceLen >= nSendLen) { m_pfunReceiver(dataBegin, nSendLen); nReveiceLen = 0; nSendLen = 0; delete dataBegin; dataBegin = nullptr; } ResetEvent(m_writeEvent); SetEvent(m_readEvent); } break; } default: std::cout<<"Wait error :" << GetLastError()<<std::endl; break; } } } void ShareMemory::int2Bytes(int nValue, int nLength, unsigned char* pResult) { if (pResult == NULL) { return; } for (int i = 0; i < nLength; i++) { pResult[i] = (char)(nValue >> 8 * (3 - i) & 0xFF); } } int ShareMemory::bytes2Int(unsigned char* pData, int nLength) { if (pData == NULL) { return 0; } int nValue = 0; for (int i = 0; i < nLength; i++) { nValue += (pData[i] & 0xFF) << (8 * (3 - i)); } return nValue; }