Windows process communication -- shared memory

Keywords: Programming Windows

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

 

Posted by blue-genie on Thu, 28 Nov 2019 06:22:46 -0800