📄 memmap.cpp
字号:
*lpOffset = lpCurPos;
}
BOOL CMemMap::DeleteID(UINT uId)
{
/********************************************************
* Remove the string
* move following data to fill the void
********************************************************/
ASSERT ( m_pMappedViews );
CheckForNewPages();
// Validate the ID
if ( uId == 0xFFFFFFFF || uId == 0xFFFFFF00 )
return FALSE;
LPBYTE lpBytePos = 0; // a navigation pointer
LPBYTE lpDebugView = 0; // enable the watch view in debug
UINT uPage = 0;
// Check if the id exists
if ( FindID(uId,&uPage,&lpBytePos) == FALSE )
return FALSE;
if (uId == 100)
int i=0;
lpDebugView = (LPBYTE)m_pMappedViews[uPage];
// Set the pointers to track the source and dest
UINT uSrcPage = uPage;
LPBYTE lpDestPos = lpBytePos;
UINT uSize = 0;
// Calc full size of the removed block
uSize = GetLength(uPage,lpBytePos);
uSize += 4/*id*/ + 4/*strlen*/;
// move pointer to end
NextID(&uPage,&lpBytePos);
// Calc page spans
UINT uRemaining = ((UINT)m_pMappedViews[uPage] + MMF_PAGESIZE);
UINT uSpanned = uPage - uSrcPage;
// setup before entering loop
if ( uSpanned ) {
// size from start (bytes to fill)
uRemaining = ((UINT)m_pMappedViews[uSrcPage] + MMF_PAGESIZE);
uRemaining -= (UINT)lpDestPos; // 8
// fill remainder of this page
memset(lpDestPos,0xFF,uRemaining); // DEBUG last 8 bytes
memmove(lpDestPos,lpBytePos,uRemaining); //
// set pointer to next block
lpBytePos += uRemaining;
lpDestPos = (LPBYTE)m_pMappedViews[uPage];
// set the data size
uRemaining = ((UINT)m_pMappedViews[uPage] + MMF_PAGESIZE);
uRemaining -= (UINT)lpBytePos; // 8
}
else {
// size from end (bytes to move)
uRemaining -= (UINT)lpBytePos;
// fill void on this page
memmove(lpDestPos,lpBytePos,uRemaining);
// set pointer to next block
lpDestPos += uRemaining;
if ( uPage < m_uPageCount-1 ) {
// Account for flags
if ( uPage == 0 )
uRemaining += 4;
// goto start of next page
uPage += 1;
lpBytePos = (LPBYTE)m_pMappedViews[uPage];
// fill remainder 0f this page
memmove(lpDestPos,lpBytePos,uSize);
// set pointers to next block
lpBytePos += uSize;
lpDestPos = (LPBYTE)m_pMappedViews[uPage];
}
else {
// no more pages, set remainder unallocated
memset(lpDestPos,0xFF,uSize);
// double null terminate
*lpDestPos = 0;
return TRUE;
}
}
// current page now starts with a void space
// uSize == size of the void
// uRemaining == size of the data
// lpDestPos == start of void
// lpBytePos == start of data
// loop through remaining pages
while ( 1 ) {
// enable the watch view
lpDebugView = lpDestPos;
// move data into void
memmove(lpDestPos,lpBytePos,uRemaining);
// reset pointers
if ( uPage < m_uPageCount-1 ) {
uPage += 1;
lpBytePos = (LPBYTE)m_pMappedViews[uPage];
lpDestPos += uRemaining;
}
else {
// no more pages
break;
}
// move from next page into void
memmove(lpDestPos,lpBytePos,uSize);
// reset the pointers
lpBytePos += uSize;
lpDestPos = (LPBYTE)m_pMappedViews[uPage];
}
// unallocate the remaining void
memset(lpBytePos,0xFF,uSize);
*lpBytePos = 0;
return TRUE;
}
UINT CMemMap::GetID(UINT uPage, LPBYTE lpOffset)
{
/***********************************************************
* Get the id but do not increase the pointers
* lpOffset should be pointing to the ID location
***********************************************************/
UINT uId = 0;
Read(&uPage,&lpOffset,4,&uId);
return uId;
}
UINT CMemMap::GetLength(UINT uPage, LPBYTE lpOffset)
{
/***********************************************************
* Get the strlen but do not increase the pointers
* lpOffset should be pointing to the ID location
***********************************************************/
UINT uSize = 0;
Read(&uPage,&lpOffset,4,NULL);
Read(&uPage,&lpOffset,4,&uSize);
return uSize;
}
UINT64 CMemMap::UsedSize()
{
/***********************************************************
* Return the actual used bytes
***********************************************************/
ASSERT ( m_pMappedViews );
CheckForNewPages();
LPBYTE lpBytePos = (LPBYTE)m_pMappedViews[0]; // a navigation pointer
UINT uPage = 0;
// First byte is reserved for flags
lpBytePos += 4;
// seek to the end of the data
while ( 1 ) {
// read 4 bytes into an int
unsigned int i = GetID(uPage,lpBytePos);
if ( i == 0xFFFFFFFF || i == 0xFFFFFF00 )
// unused memory
break;
NextID(&uPage,&lpBytePos);
}
UINT uUsed = (UINT)m_pMappedViews[uPage] + (UINT)lpBytePos;
uUsed += (uPage * MMF_PAGESIZE);
return uUsed;
}
UINT CMemMap::Count()
{
/***********************************************************
* Return the count of items being stored
***********************************************************/
ASSERT ( m_pMappedViews );
CheckForNewPages();
LPBYTE lpBytePos = (LPBYTE)m_pMappedViews[0]; // a navigation pointer
UINT uPage = 0;
UINT uiCount = 0;
// First byte is reserved for flags
lpBytePos += 4;
// Count all the strings
while ( 1 ) {
// read 4 bytes into an int
unsigned int i = GetID(uPage,lpBytePos);
if ( i == 0xFFFFFFFF || i == 0xFFFFFF00 )
// unused memory
break;
NextID(&uPage,&lpBytePos);
uiCount++;
}
return uiCount;
}
//////////////////////////////////////////////////////////////////////
// Single Writer / Multi Reader Written by: Alex Farber alexm@cmt.co.il
//////////////////////////////////////////////////////////////////////
BOOL CMemMap::InitProtect(LPCTSTR szName,DWORD dwWait)
{
/************************************************************
* Create the unique names
************************************************************/
ASSERT ( szName );
int iLen = _tcslen(szName);
iLen += 6 * sizeof(TCHAR);
try
{
m_sMutexName = new TCHAR [iLen];
m_sSemReadersName = new TCHAR [iLen];
m_sSemWritersName = new TCHAR [iLen];
m_sMemFileName = new TCHAR [iLen];
_stprintf(m_sMutexName, _T("%s_Mutex"), szName);
_stprintf(m_sSemReadersName, _T("%s_SemRd"), szName);
_stprintf(m_sSemWritersName, _T("%s_SemWr"), szName);
_stprintf(m_sMemFileName, _T("%s_MemFl"), szName);
}
catch (...)
{
TRACE ( _T("Failed to InitProtect") );
}
// keep time interval
m_dwMilliseconds = dwWait;
return InitSyncObjects();
}
BOOL CMemMap::EndProtect()
{
/************************************************************
* Clean up
************************************************************/
delete [] m_sMutexName;
delete [] m_sSemReadersName;
delete [] m_sSemWritersName;
delete [] m_sMemFileName;
if ( m_hFileMapping )
if ( m_pViewOfFile )
if ( UnmapViewOfFile(m_pViewOfFile) )
CloseHandle(m_hFileMapping);
if ( m_hMutex )
CloseHandle(m_hMutex);
if ( m_hsemWriters )
CloseHandle(m_hsemWriters);
if ( m_hsemReaders )
CloseHandle(m_hsemReaders);
return TRUE;
}
BOOL CMemMap::InitSyncObjects()
{
/************************************************************
* Init the mutex, semaphores and mapped file
************************************************************/
// create semaphore for waiting readers
m_hsemReaders = CreateSemaphore(NULL,0,MAXLONG,m_sSemReadersName);
if ( ! m_hsemReaders ) {
TRACE ( _T("Failed to CreateSemaphore") );
return FALSE;
}
// create semaphore for waiting writers
m_hsemWriters = CreateSemaphore(NULL,0,MAXLONG,m_sSemWritersName );
if ( ! m_hsemWriters ) {
TRACE ( _T("Failed to CreateSemaphore") );
return FALSE;
}
// crate mutex protecting access to other members
m_hMutex = CreateMutex(NULL,FALSE,m_sMutexName );
if ( ! m_hMutex ) {
TRACE ( _T("Failed to CreateMutex") );
return FALSE;
}
// create file mapping to keep counters
m_hFileMapping = CreateFileMapping( INVALID_HANDLE_VALUE,
NULL,
PAGE_READWRITE,
0,
sizeof(RW_COUNTERS),
m_sMemFileName);
if ( ! m_hFileMapping ) {
TRACE ( _T("Failed to CreateFileMapping for mutex") );
return FALSE;
}
m_pViewOfFile = MapViewOfFile(m_hFileMapping,FILE_MAP_ALL_ACCESS,0,0,0);
if ( ! m_pViewOfFile ) {
TRACE ( _T("Failed to MapViewOfFile for mutex") );
return FALSE;
}
// get pointers to counters
RW_COUNTERS* pCounters = (RW_COUNTERS*) m_pViewOfFile;
m_pnActive = &pCounters->m_nActive;
m_pnWaitingReaders = &pCounters->m_nWaitingReaders;
m_pnWaitingWriters = &pCounters->m_nWaitingWriters;
return TRUE;
}
BOOL CMemMap::WaitToRead()
{
/************************************************************
* Attempt to read the shared file
************************************************************/
// Ensure exclusive access to the member variables
if ( WaitForSingleObject(m_hMutex, m_dwMilliseconds) != WAIT_OBJECT_0 )
return FALSE;
// Check for writers waiting or writing
bool fResourceWritePending = (*m_pnWaitingWriters || (*m_pnActive < 0));
// Check if can read
if ( fResourceWritePending )
(*m_pnWaitingReaders)++;
else
(*m_pnActive)++;
// Allow other clients to attempt reading/writing
ReleaseMutex(m_hMutex);
// Wait for write to complete
if ( fResourceWritePending ) {
// This thread must wait
if ( WaitForSingleObject(m_hsemReaders,m_dwMilliseconds) != WAIT_OBJECT_0 ) {
// try to make rollback
if ( WaitForSingleObject(m_hMutex,m_dwMilliseconds) == WAIT_OBJECT_0 ) {
(*m_pnWaitingReaders)--; // rollback
ReleaseMutex(m_hMutex);
}
return FALSE;
}
}
return TRUE;
}
BOOL CMemMap::WaitToWrite()
{
/************************************************************
* Attempt to write to the shared file
************************************************************/
// Wait for access
if ( WaitForSingleObject(m_hMutex, m_dwMilliseconds) != WAIT_OBJECT_0 )
return FALSE;
// Check other threads
BOOL fResourceOwned = (*m_pnActive != 0);
// Check if can write
if ( fResourceOwned )
(*m_pnWaitingWriters)++;
else
*m_pnActive = -1;
// Allow other clients to attempt reading/writing
ReleaseMutex(m_hMutex);
// Wait
if ( fResourceOwned ) {
// This thread must wait
if ( WaitForSingleObject(m_hsemWriters,m_dwMilliseconds) != WAIT_OBJECT_0 ) {
// try to make rollback
if ( WaitForSingleObject(m_hMutex,m_dwMilliseconds) == WAIT_OBJECT_0 ) {
(*m_pnWaitingWriters)--; // rollback
ReleaseMutex(m_hMutex);
}
return FALSE;
}
}
return TRUE;
}
BOOL CMemMap::Done()
{
/************************************************************
* Release the shared file
************************************************************/
// Get the mutex
if ( WaitForSingleObject(m_hMutex, m_dwMilliseconds) != WAIT_OBJECT_0 )
return FALSE;
if (*m_pnActive > 0)
// Readers have control so a reader must be done
(*m_pnActive)--;
else
// Writers have control so a writer must be done
(*m_pnActive)++;
HANDLE hsem = NULL; // Assume no threads are waiting
LONG lCount = 1; // Assume only 1 waiter wakes; always true for writers
if ( *m_pnActive == 0 )
{
if ( *m_pnWaitingWriters > 0 )
{
// Writers are waiting and they take priority over readers
*m_pnActive = -1; // A writer will get access
(*m_pnWaitingWriters)--; // One less writer will be waiting
hsem = m_hsemWriters; // Writers wait on this semaphore
// NOTE: The semaphore will release only 1 writer thread
}
else if ( *m_pnWaitingReaders > 0 )
{
// Readers are waiting and no writers are waiting
*m_pnActive = *m_pnWaitingReaders; // All readers will get access
*m_pnWaitingReaders = 0; // No readers will be waiting
hsem = m_hsemReaders; // Readers wait on this semaphore
lCount = *m_pnActive; // Semaphore releases all readers
}
else
{
// There are no threads waiting at all; no semaphore gets released
}
}
// Allow other threads to attempt reading/writing
ReleaseMutex(m_hMutex);
if (hsem != NULL)
{
// Some threads are to be released
ReleaseSemaphore(hsem, lCount, NULL);
}
return TRUE;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -