http://www.codeproject.com/KB/threads/sm.aspx
等有时间了过来翻译一下。
Motivation
Sometimes you need to share some values across several processes. There are some ways, provided by system, but there is no simple way to share simple values like DWORD
s or strings. And of course, synchronization is also required in this case.
Description of solution
I was inspired by PJ Naughter's solution, but I wanted more. I wanted structured shared memory, with variables, synchronization and wait functionality within it.
Internal structure
Variables are shared within an unnamed memory file. This 'file' (or better, block of memory) is allocated in the page file. It is not possible to create growable file of this type, but I did not require it. The internal structure of this memory is as follows:
DWORD DWORD ValueHeader[0] value 0 ValueHeader[1] value 1 .............. ValueHeader[n] value n
The first DWORD
is the number of values within memory. The second DWORD
is the memory size; it includes these two DWORD
s too. ValueHeader
is a structure defined as:
typedef struct _tagValueHeader { WCHAR wszValueName[VAR_NAME_LENGTH]; DWORD dwLength; } ValueHeader;
Member wszValueName
is value name, dwLength
is length in bytes of the value, which follows this structure. As you can see, the actual value is stored as several bytes. There is no type checking of the value's type. It is not allowed access the variable directly. Instead of that, the class provides several methods to access values. It allows synchronized access, and it is possible to wait for value or memory changes.
CSharedMemory public class members
Construction and destructions
CSharedMemory
~CSharedMemory
General methods
GetMemName
IsCreated
GetMemSize
AmIFirst
GetLastError
Access control methods
SetSdMem
GetSdMem
SetSdSem
GetSdSem
SetSaEvent
Value management methods
AddValue
AddDwordValue
DeleteValue
ExistValue
GetVariablesCount
GetValueInfo
Value access methods
SetValue
GetValue
Wait methods
WaitForMemChange
WaitForValueChange
WaitForMultipleValuesChanges
Interlocked* methods
InterlockedIncrement
InterlockedDecrement
InterlockedExchange
InterlockedTestExchange
InterlockedCompareExchange
InterlockedExchangeAdd
Direct memory access methods
Read
Write
DEBUG methods
AssertValid
Dump
CSharedMemory::CSharedMemory
-
CSharedMemory(TCHAR *szName, DWORD dwSize = DEF_SHARED_SIZE, PINITMEMORY InitMemoryProcedure = NULL, void *pInitProcParam = NULL, LPSECURITY_ATTRIBUTES lpsaAttributes = NULL);
Remarks
Constructor for the class. It creates shared memory named
szName
, ofdwSize<
size. When you want initialize memory at the same place as you declare it, you can define aninitializer function
, defined as:void InitMemory(CSharedMemory *pMem, void *pInitProcParam)
And you can pass its address to the constructor. This solution allows you write shorter code like:
... CSharedMemory sh_mem("MemoryName",1024,InitMemory); ...
'Initialize' means, for example to add some variables. If you need to pass your own initialization value, then you can specify it in the
pInitProcParam
parameter. If you don't provide this value at the construction time, then constructor will passNULL
to your initializer function.lpsaAttributes
defines access control rights and security attributes of the memory mapped file, semaphore and events created inside theCSharedMemory
object. For more information see SECURITY_ATTRIBUTES. -
~CSharedMemory();
Remarks
Destructor for the class. It frees all allocated resources.
-
CString GetMemName(void);
Remarks
Returns name of the shared memory.
-
BOOL IsCreated(void);
Remarks
Returns
TRUE
if memory was successfully created. -
DWORD GetMemSize(void);
Remarks
Returns size of memory.
-
BOOL AmIFirst(void);
Remarks
Returns
TRUE
, if caller was first, who created memory. -
DWORD GetLastError(void);
Remarks
Returns a Win32 error code that describes the best last error inside a call made to the object.
-
BOOL SetSdMem(SECURITY_INFORMATION SecurityInformation, PSECURITY_DESCRIPTOR SecurityDescriptor);
Remarks
This method sets the security descriptor for memory mapped file. If it fails, it returns
FALSE
, otherwiseTRUE
. Call CSharedMemory::GetLastError() to retrieve error code. See also SetKernelObjectSecurity(). -
BOOL GetSdMem(SECURITY_INFORMATION RequestedInformation, PSECURITY_DESCRIPTOR pSecurityDescriptor, DWORD nLength, LPDWORD lpnLengthNeeded);
Remarks
This method gets the security descriptor of the memory mapped file. If it fails, it returns
FALSE
, otherwiseTRUE
. Call CSharedMemory::GetLastError() to retrieve error code. See also GetKernelObjectSecurity(). -
BOOL SetSdSem(SECURITY_INFORMATION SecurityInformation, PSECURITY_DESCRIPTOR SecurityDescriptor);
Remarks
This method sets the security descriptor of the semaphore, which synchronizes access to shared memory. If it fails, returns
FALSE
, otherwiseTRUE
. Call CSharedMemory::GetLastError() to retrieve the error code. See also SetKernelObjectSecurity(). -
BOOL GetSdSem(SECURITY_INFORMATION RequestedInformation, PSECURITY_DESCRIPTOR pSecurityDescriptor, DWORD nLength, LPDWORD lpnLengthNeeded);
Remarks
This method gets security descriptor of the semaphore, which synchronizes access to shared memory. If it fails, it returns
FALSE
, otherwiseTRUE
. Call CSharedMemory::GetLastError() to retrieve the error code. See also GetKernelObjectSecurity(). -
BOOL SetSaEvent(LPSECURITY_ATTRIBUTES lpsaAttributes);
Remarks:
This method sets internal variable to security attributes, which are used to protect internal events object. These events are used to 'wait' for changes in the memory or variable. If it fails, it returns
FALSE
, otherwiseTRUE
. Call -
BOOL AddValue(const TCHAR *szName, DWORD size, void *pDefaultData = NULL);
Remarks
This method adds new value named
szName
. It creates a new entry within memory and reserves space ofsize
for new value. If it fails, returnsFALSE
, otherwiseTRUE
. You can use the last parameter to set its value after it is created. Call CSharedMemory::GetLastError() to retrieve the error code. -
BOOL AddDwordValue(const TCHAR *szName, DWORD dwDefault = 0);
Remarks
Method adds new
DWORD
value namedszName
. It creates a new entry within memory and reserves space ofsize
for new value. If it fails, it returnsFALSE
, otherwiseTRUE
. You can use last parameter to set its value after it is created. Call CSharedMemory::GetLastError() to retrieve the error code. -
BOOL DeleteValue(TCHAR *szName);
Remarks
This method deletes the value named
szName
from memory, it frees used space and freed memory is filled with zeros. If it fails, it returnsFALSE
, otherwiseTRUE
. Call CSharedMemory::GetLastError() to retrieve error code. -
BOOL ExistValue(TCHAR *szName);
Remarks
This method returns
TRUE
, if variableszName
exists within memory. If it fails, returnsFALSE
, otherwiseTRUE
. Call CSharedMemory::GetLastError() to retrieve the error code (when constructor failed, this method returnsFALSE
, but CSharedMemory::GetLastError() returns a different error code). -
DWORD GetVariablesCount(void);
Remarks
This method returns the number of values stored in the memory. If it fails, it returns
FALSE
, otherwiseTRUE
. Call CSharedMemory::GetLastError() to retrieve the error code. -
BOOL GetValueInfo(DWORD dwIndex, ValueHeader *pVarInfo);
Remarks
This method copies value information of the format
ValueHeader
to memory pointed bypVarInfo
. If it fails, returnsFALSE
, otherwiseTRUE
. Call CSharedMemory::GetLastError() to retrieve the error code. -
BOOL SetValue(TCHAR *szName, void *bData, DWORD dwLength);
Remarks
This method sets the variable named
szName
to value pointed to bybData
. Length of the data at addressbData
is passed as the last parameter. It can be less then allocated length within shared memory. In this case the rest of the allocated buffer is filled with zeros. If it fails, it returnsFALSE
, otherwiseTRUE
. Call CSharedMemory::GetLastError() to retrieve the error code. -
BOOL GetValue(TCHAR *szName, void *bData, LPDWORD dwLength);
Remarks
This method retrieves thevalue of the variable
szName
. Data is stored at addressbData
. The length stored atbData
is returned indwLength
. It is possible to pass inbData
NULL, then the method returns indwLength
the required buffer length. If it fails, it returnsFALSE
, otherwiseTRUE
. Call CSharedMemory::GetLastError()to retrieve the error code. -
DWORD WaitForMemChange(DWORD dwMilliseconds = INFINITE);
Remarks
This method waits for any change in the structure of the shared memory. 'Change' means add or delete a variable. When you do not use variables, but
direct access functions
, then you can use this method to wait for the changes. For direct access see CSharedMemory::Read() or CSharedMemory::Write(). If it fails, it returnsWAIT_FAILED
value, see also WaitForSingleObject() . -
DWORD WaitForValueChange(TCHAR *szName, DWORD dwMilliseconds = INFINITE);
Remarks
This methods waits for changes of value. It also returns, when a variable is deleted. If it fails, itreturns
WAIT_FAILED
value, see also WaitForSingleObject(). -
DWORD CSharedMemory::WaitForMultipleValuesChanges(CStringArray & str,BOOL bWaitForAll , DWORD dwMilliseconds =INFINITE );
Remarks
This methods waits for changes of values. It also returns when variables are deleted. You can choose to wait for change of one or several values. If it fails, it returns
WAIT_FAILED
value, see also WaitForMultipleObject().All Interlocked* functions are described in the MSDN. Methods of
CSharedMemory
work the same way, except they returnTRUE
/FALSE
as an indicator of success, and the return value of emulated functions is returned through a pointer (usually the last optional parameter). -
BOOL InterlockedIncrement(TCHAR *szName, LPLONG plNewVal = NULL);
Remarks
See also InterlockedIncrement().
-
BOOL InterlockedDecrement(TCHAR *szName, LPLONG plNewVal = NULL);
Remarks
See also InterlockedDecrement().
-
BOOL InterlockedExchange(TCHAR *szTargetName, LONG lNewVal, LPLONG plPrevValue = NULL);
Remarks
See also InterlockedExchange().
-
BOOL InterlockedTestExchange(TCHAR *szTargetName, LONG lOldValue, LONG lNewValue, LPLONG plPrevValue = NULL);
Remarks
See also InterlockedTestExchange().
-
BOOL InterlockedCompareExchange(TCHAR *szTargetName, LONG lExchange, LONG lComperand, LPLONG plIntiVal = NULL);
Remarks
See also InterlockedCompareExchange().
-
BOOL InterlockedExchangeAdd(TCHAR *szTargetName, LONG lIncrement, LPLONG plIntiVal = NULL);
Remarks
See also InterlockedExchangeAdd().
-
BOOL Read(BYTE *pbData, DWORD dwLength, DWORD dwOffset = 0);
Remarks
This method reads
dwLength
bytes from offsetdwOffset
within memory. It is allowed to access shared memory this way only when it contains no variables. Method writes data at the addresspbData
. If it fails, it returnsFALSE
, otherwiseTRUE
. Call CSharedMemory::GetLastError() to retrieve the error code. -
BOOL Write(BYTE *pbData, DWORD dwLength, DWORD dwOffset = 0);
Remarks
Method writes
dwLength
bytes frompbData
at the offsetdwOffeset
within the shared memory. It is allowed to access shared memory this way only when it contains no variables. If it fails, it returnsFALSE
, otherwiseTRUE
. Call CSharedMemory::GetLastError() to retrieve the error code. -
void AssertValid(void);
Remarks
This methof performs a validity check on this object by checking its internal state.
-
void Dump(CDumpContext & dc);
Remarks
Dumps the contents of shared memory to a
CDumpContext
object.
CSharedMemory::~CSharedMemory
CSharedMemory::GetMemName
CSharedMemory::IsCreated
CSharedMemory::GetMemSize
CSharedMemory::AmIFirst
CSharedMemory::GetLastError
CSharedMemory::SetSdMem
CSharedMemory::GetSdMem
CSharedMemory::SetSdSem
CSharedMemory::GetSdSem
CSharedMemory::SetSaEvent
CSharedMemory::GetLastError() to retrieve error code.CSharedMemory::AddValue
CSharedMemory::AddDwordValue
CSharedMemory::DeleteValue
CSharedMemory::ExistValue
CSharedMemory::GetVariablesCount
CSharedMemory::GetValueInfo
CSharedMemory::SetValue
CSharedMemory::GetValue
CSharedMemory::WaitForMemChange
CSharedMemory::WaitForValueChange
CSharedMemory::WaitForMultipleValuesChanges
CSharedMemory::InterlockedIncrement
CSharedMemory::InterlockedDecrement
CSharedMemory::InterlockedExchange
CSharedMemory::InterlockedTestExchange
CSharedMemory::InterlockedCompareExchange
CSharedMemory::InterlockedExchangeAdd
CSharedMemory::Read
CSharedMemory::Write
CSharedMemory::AssertValid
CSharedMemory::Dump
Usage
I have provided a simple demo program to demonstrate usage of the CSharedMemory
class. A shared block of the memory exists within the system until the last instance of the CSharedMemory
class is destroyed. CSharedMemory
is UNICODE enabled; it will work in UNICODE or ANSI programs. It is possible to share the same memory from both types of programs. CSharedMemory
uses simple diagnostic functions from Helpers.h and Helpers.cpp
Demo program
The demo program provides an interface to the many methods of CSharedMemory
, and you can use more instances of it to play with CSharedMemory
and see how it works. It also demonstrates usage of the class.