📄 sharedmemory.h
字号:
};
void Close()
{
if (WaitForSingleObject(m_hClosed, 0) == WAIT_TIMEOUT)
{
// Indicate that this instance is closed
SetEvent(m_hClosed);
// Release your own mutex. This will auitomatically signal
// the other instance of this class that this instance broke
// the connection.
ReleaseMutex(m_hSharedMemoryMutex[m_nInstanceID]);
// The writequeue may still contain elements, empty
// it.
EmptyWriteQueue();
WaitForSingleObject(m_hQueueThread, INFINITE);
CloseHandle(m_hQueueMutex);
CloseHandle(m_hDataInQueue);
m_hQueueMutex = NULL;
m_hDataInQueue = NULL;
// Cleanup some stuff.
CloseHandle(m_hDataWrit[0]);
CloseHandle(m_hDataWrit[1]);
CloseHandle(m_hDataRead[0]);
CloseHandle(m_hDataRead[1]);
m_hDataWrit[0] = NULL;
m_hDataWrit[1] = NULL;
m_hDataRead[0] = NULL;
m_hDataRead[1] = NULL;
UnmapViewOfFile(m_pSize);
m_pSharedMemory[0] -= sizeof(int);
m_pSharedMemory[1] -= sizeof(int);
UnmapViewOfFile(m_pSharedMemory[0]);
UnmapViewOfFile(m_pSharedMemory[1]);
CloseHandle(m_hSharedMemory[0]);
CloseHandle(m_hSharedMemory[1]);
CloseHandle(m_hSharedMemoryMutex[0]);
CloseHandle(m_hSharedMemoryMutex[1]);
}
};
int Write(void *pData, int nDataSize, DWORD dwTimeOut)
{
// The 'Write' and 'WriteToQueue' functions can be used promiscously.
// This function writes to the shared memory pool, it can only write
// to that pool if existing data in the pool has been read by the
// other instance of this class.
// If this function returns MEM_ERROR_OTHERPARTY, the calling
// process should close the connection and re-open it to create a new
// valid connection.
HANDLE hWait[3];
hWait[0] = m_hClosed;
hWait[1] = m_hSharedMemoryMutex[m_nOtherInstanceID];
hWait[2] = m_hDataRead[m_nOtherInstanceID];
DWORD dwWaitResult = WaitForMultipleObjects(3, hWait, FALSE, dwTimeOut);
switch(dwWaitResult)
{
case WAIT_OBJECT_0 + 2:
if (nDataSize > *m_pSize)
return MEM_ERROR_DATASIZE;
// Data was read from the shared memory pool, write new data
// and notify any listener that new data was written.
memcpy(m_pSharedMemory[m_nOtherInstanceID], pData, nDataSize);
SetEvent(m_hDataWrit[m_nOtherInstanceID]);
return MEM_SUCCESS;
case WAIT_OBJECT_0:
// The close function of this instance was called.
return MEM_ERROR_CLOSED;
case WAIT_OBJECT_0 + 1:
// The other instance closed.
// Since we locked the mutex by waiting for it, we have to release
// it again.
ReleaseMutex(m_hSharedMemoryMutex[m_nOtherInstanceID]);
return MEM_ERROR_OTHERPARTY;
case WAIT_ABANDONED_0 + 1:
// The other instance left without a trace, this means probably that
// it crashed.
// Since we locked the mutex by waiting for it, we have to release
// it again.
ReleaseMutex(m_hSharedMemoryMutex[m_nOtherInstanceID]);
return MEM_ERROR_OTHERPARTY;
case WAIT_FAILED:
if (!m_hDataRead[m_nOtherInstanceID])
return MEM_ERROR_CLOSED;
// I don't know wat happened, you should call 'GetLastError()'.
return MEM_ERROR_UNKNOWN;
case WAIT_TIMEOUT:
// There was a timeout, the other party has not yet read previous data.
return MEM_ERROR_TIMEOUT;
}
return MEM_ERROR_UNKNOWN;
}
int WriteToQueue(void *pData, int nDataSize)
{
// The 'Write' and 'WriteToQueue' functions can be used promiscously.
// This function is somewhat the same as the previous function, however,
// this function is non-blocking. As long as the connection is valid this
// function can write new data into a queue. The queue is read by a thread
// that calls the previous 'Write' function.
HANDLE hWait[3];
hWait[0] = m_hClosed;
hWait[1] = m_hSharedMemoryMutex[m_nOtherInstanceID];
hWait[2] = m_hQueueMutex;
switch (WaitForMultipleObjects(3, hWait, FALSE, INFINITE))
{
case WAIT_OBJECT_0:
return MEM_ERROR_CLOSED;
case WAIT_OBJECT_0 + 2:
{
if (nDataSize > *m_pSize)
return MEM_ERROR_DATASIZE;
CWriteQueue *pNew = new CWriteQueue(*m_pSize);
memcpy(pNew->pData, pData, *m_pSize);
if (!m_pFirst)
m_pFirst = pNew;
else
{
CWriteQueue *pCurrent = m_pFirst;
while (pCurrent->pNext)
pCurrent = pCurrent->pNext;
pCurrent->pNext = pNew;
}
SetEvent(m_hDataInQueue);
ReleaseMutex(m_hQueueMutex);
}
return MEM_SUCCESS;
case WAIT_OBJECT_0 + 1:
// The other instance closed.
// Since we locked the mutex by waiting for it, we have to release
// it again.
ReleaseMutex(m_hSharedMemoryMutex[m_nOtherInstanceID]);
return MEM_ERROR_OTHERPARTY;
case WAIT_ABANDONED_0 + 1:
// The other instance left without a trace, this means probably that
// it crashed.
// Since we locked the mutex by waiting for it, we have to release
// it again.
ReleaseMutex(m_hSharedMemoryMutex[m_nOtherInstanceID]);
return MEM_ERROR_OTHERPARTY;
case WAIT_FAILED:
// This can happen when the connection was not opened yet.
// It is caused by an invalid or NULL handle.
if (!m_hQueueMutex)
return MEM_ERROR_CLOSED;
// This must never happen.
return MEM_ERROR_UNKNOWN;
}
return MEM_ERROR_UNKNOWN;
}
int Read(void *pData, int nDataSize, DWORD dwTimeOut)
{
// This function reads from the shared memory pool, it can
// only read data when data was written to the pool.
// It is always a blocking function.
// It reads data that was written to the shared memory pool by
// the 'Write' or 'WriteToQueue' functions.
HANDLE hWait[3];
hWait[0] = m_hDataWrit[m_nInstanceID];
hWait[1] = m_hClosed;
hWait[2] = m_hSharedMemoryMutex[m_nOtherInstanceID];
DWORD dwWaitResult = WaitForMultipleObjects(3, hWait, FALSE, dwTimeOut);
switch(dwWaitResult)
{
case WAIT_OBJECT_0:
// This happens when data is written into the shared memory pool.
// It indicates that the data can be copied into a memory
// buffer.
if (nDataSize > *m_pSize)
return MEM_ERROR_DATASIZE;
memcpy(pData, m_pSharedMemory[m_nInstanceID], nDataSize);
SetEvent(m_hDataRead[m_nInstanceID]);
return MEM_SUCCESS;
case WAIT_OBJECT_0 + 1:
// This happens when no connection was made yet, or this
// instance was closed.
return MEM_ERROR_CLOSED;
case WAIT_OBJECT_0 + 2:
// This happens when the other party closes its connection.
ReleaseMutex(m_hSharedMemoryMutex[m_nOtherInstanceID]);
return MEM_ERROR_OTHERPARTY;
case WAIT_ABANDONED_0 + 2:
// This happens when the other party gracefully closes its connection.
// This can be caused by an unexpected termination of the host
// process of the other instance.
ReleaseMutex(m_hSharedMemoryMutex[m_nOtherInstanceID]);
return MEM_ERROR_OTHERPARTY;
case WAIT_FAILED:
// This can happen when the connection was not opened yet.
// It is caused by an invalid or NULL handle.
if (!m_hDataWrit[m_nInstanceID])
return MEM_ERROR_CLOSED;
return MEM_ERROR_UNKNOWN;
case WAIT_TIMEOUT:
// This indicates that the maximum wait time (dwTimeOut) has passed.
return MEM_ERROR_TIMEOUT;
}
return MEM_ERROR_UNKNOWN;
}
private:
void EmptyWriteQueue()
{
// This private function avoids memory leaking of items in the send-queue.
while (m_pFirst && WaitForSingleObject(m_hQueueMutex, INFINITE) == WAIT_OBJECT_0)
{
if (m_pFirst)
{
// First get the first element of the queue
CWriteQueue *pQueue = m_pFirst;
m_pFirst = pQueue->pNext;
delete pQueue;
}
ReleaseMutex(m_hQueueMutex);
}
}
static void QueueThread(void *pArg)
{
// This thread writes every packet that enteres the queue to the shared memory pool.
// It ensures that the 'WriteToQueue' function is nonblocking.
// The queue access is mutexed to avoid simultaneous access to the queue by
// this thread and the 'WriteToQueue' function.
CSharedMemory *pThis = (CSharedMemory*)pArg;
HANDLE hWait[2] = {pThis->m_hClosed, pThis->m_hDataInQueue};
bool bQuit = false;
while (!bQuit)
{
switch (WaitForMultipleObjects(2, hWait, FALSE, INFINITE))
{
case WAIT_OBJECT_0 + 1:
{
BYTE *pData = NULL;
while (pThis->m_pFirst && WaitForSingleObject(pThis->m_hQueueMutex, INFINITE) == WAIT_OBJECT_0)
{
if (pThis->m_pFirst)
{
// First get the first element of the queue
CWriteQueue *pQueue = pThis->m_pFirst;
pData = new BYTE[*pThis->m_pSize];
memcpy(pData, pThis->m_pFirst->pData, *pThis->m_pSize);
pThis->m_pFirst = pQueue->pNext;
delete pQueue;
ReleaseMutex(pThis->m_hQueueMutex);
pThis->Write(pData, *pThis->m_pSize, INFINITE);
delete [] pData;
}
else
ReleaseMutex(pThis->m_hQueueMutex);
}
}
break;
case WAIT_OBJECT_0:
bQuit = true;
break;
}
}
}
private:
// We will use two shared memory pools to create a transparant memory 'pipe'.
// One pool will be used as destination for one instance, and source for the other
// instance, the other will be used the other way around.
// The two mutexes will indicate which instance is already available.
HANDLE m_hSharedMemoryMutex[2];
int m_nInstanceID;
int m_nOtherInstanceID;
HANDLE m_hSharedMemory[2];
BYTE* m_pSharedMemory[2];
int* m_pSize;
HANDLE m_hClosed; // This handle indicates wether this instance
// is open or closed.
HANDLE m_hDataWrit[2];
HANDLE m_hDataRead[2];
HANDLE m_hSecondInstanceAvailable;
// Queue stuff
HANDLE m_hQueueThread;
HANDLE m_hDataInQueue;
CWriteQueue *m_pFirst;
HANDLE m_hQueueMutex;
};
#endif // !defined(AFX_SHAREDMEMORY_H__86467BA6_5AFA_11D3_863D_00A0244A9CA7__INCLUDED_)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -