Ultimate Shared Memory: A Flexible Class for Interprocess Memory Sharing






4.81/5 (22 votes)
A flexible memory sharing class across processes and threads with locking support
- GitHub: Part of my Multithreading tools: https://github.com/WindowsNT/mt
Introduction
This is a template class for sharing memory across threads or processes in Windows. It provides locking mechanisms, notifications and more!
Using the Code
Instantiation of the Class
// usm(const wchar_t* string_id = 0,bool Init = false,size_t csz = 1048576,DWORD MaxTh = 100)
usm<char> sm(L"{4BF41A4E-ACF9-4E1D-A479-14DE9FF83BC2}",false,1000,100);
string_id
is astring
that uniquely identifies kernel objects for this shared memory. All instances ofusm
that use the samestring_id
are accessing the same memory. It's recommended to use aCLSID
value to avoid possible collisions with other applications usingusm
.
If you pass0
, then the object is left uninitialized. To initialize the object, you must callCreateInit
which takes the same arguments as the constructor.Init
specifies whether initialization of the object must be included in the constructor. If this istrue
and an error occurs, the constructor throws an exception.csz
specifies the number of items to allocate. Total memory allocation iscsz*sizeof(char)
in the above example.MaxTh
is the maximum number of threads that will be accessing the shared memory. This must be the same number in any instances of the class that share the same string_id, or memory corruption will occur.
The library allocates memory to store events for each thread, so MaxTh
must be the same in all instances of the class that use the same memory (i.e., same string_id
).
Initialization of the Class
// int Initialize();
This function creates the kernel object handles required for synchronization. Calling End()
destroys these handles. Initialize()
returns 1
on success, and -1
on error. If Initialize()
fails, End()
cleans up all remaining handles. The destructor of the class also calls End()
.
If another thread is writing to the shared memory, this function waits until the writing is over.
Reading Shared Memory
// unsigned long long ReadData(T* b,size_t sz,size_t offset = 0,bool FailIfNotReady = false);
This function (which internally calls BeginRead()
and EndRead()
) does the following:
- If
FailfNotReady
istrue
and any writing thread has not finished writing, the function immediately returns-1
. IfFailIfNotReady
isfalse
, the function waits until any writing thread has finished writing. - Marks the current state of the calling thread as reading. This forces any writing thread to wait until reading is finished.
- Reads the data.
- Marks the state of the calling thread as not reading. This allows any writing thread to resume (as long as there are no more reading threads).
- Returns the same value as
sz
.
Writing Shared Memory
// unsigned long long WriteData(const T* b,size_t sz,size_t offset = 0,bool FailIfNotReady = false);
This function (which internally calls BeginWrite()
and EndWrite()
) does the following:
- If
FailfNotReady
istrue
and any other thread is writing or reading, the function immediately returns-1
. IfFailIfNotReady
isfalse
, the function waits until any other writing or reading thread has finished. - Marks the current state of the calling thread as writing. This forces any other thread (reading or writing) to wait until writing is finished. This also forces any thread that is initializing the object with
Initialize()
to wait. - Writes the data.
- Marks the state of the calling thread as not writing. This allows any other writing or reading thread to resume. The function also sets an event that the memory has been written.
- Returns the same value as
sz
.
If you need the pointer to the data, you can call BeginRead()
(which must be followed by a call to EndRead()
) and BeginWrite()
(which must be followed by a call to EndWrite()
).
const T* BeginRead(bool FailOnNotReady = false);
void EndRead();
T* BeginWrite(bool FailOnNotReady = false);
void EndWrite();
Notifications
// DWORD NotifyOnRead(bool Wait);
// DWORD NotifyWrite(bool Wait);
- If you call
NotifyOnRead
, this function withWait == false
, then the function returns:-1
if the function fails-2
if there are no other registered threadsWAIT_TIMEOUT
if any thread is still readingWAIT_OBJECT_0
or a greater value if any of the reading threads has finished
- If you call
NotifyOnRead
withWait == true
, the return values are the same, except that the function does not return if all threads are still reading.
NotifyOnWrite
returns WAIT_OBJECT_0
if a thread has just finished writing (note that this event is auto-reset). If a thread is not writing or still writing, NotifyOnWrite
either returns WAIT_TIMEOUT
(if you call it with Wait == false
) or it waits until a thread has completed writing.
Hopefully, this class will be helpful for you. It's already very helpful for me.
Good luck!
History
- 2/11/2014 - Added the ability to initialize later, and added copy constructor and operator
=
, and added offset to read/write functions - 1/11/2014 - First release