Contents
SharedMemoryObject

Overview

Shared memory objects that use the Boost Interprocess library.

This documentation covers two classes which are similar in usage:

The semantic difference between these two classes is that instances of USharedMemoryObject require a call to remap() in child processes after forking, whilst instances of MSharedMemoryObject do not. The other difference between the two classes is that MSharedMemoryObject uses half a kilobyte of shared memory for metadata, whilst instances of USharedMemoryObject do not.

As operating systems generally allocate entire pages for shared memory (a page is typically 4KB), MSharedMemoryObject instances generally use the same amount of memory as USharedMemoryObject, unless your object has a size of between 4096N + 3584 and 4096(N+1), where N is an unsigned integer.

Note also that as shared memory is typically allocated in 4k pages, a whole page will be allocated even if your object size is a single byte. It is thus not efficient to create a large number of managed/unmanaged shared memory object instances each containing a small object. If a large number of small objects need to be shared across multiple processes, the efficient approach is to create a holder class of these objects and then to create a single managed/unmanaged shared memory object of the holder.

These template classes encapsulate calls to the Boost Interprocess library in order to manage the lifetime of a shared memory object, and provide a simple API to construct/open and use the object.

The shared memory object classes are useful when a simple approach to creating a typed shared memory object is desired. They can also act as a tutorial introduction into using shared memory via the Boost Interprocess library. More advance use of shared memory can then follow by direct use of the Boost library.

Note that when using the shared memory object classes, the type T must have a POD type structure. If the type contains pointers, the objects pointed to will not share and consequently your application will be defective. If non-POD data structures are required to be shared across multiple processes, advanced use of the Boost Interprocess library is recommended.

Quick start

#include <Balau/Interprocess/MSharedMemoryObject.hpp>
#include <Balau/Interprocess/USharedMemoryObject.hpp>

There are two types of constructors in these classes:

The first constructor creates an automatically named shared memory object by generating a name prefix based on a UUID.

The second set of constructors take a dummy object specifying whether to create or open the shared memory object, plus the name of the shared memory.

Forked processes

Forking is a simple way to construct and use the share memory object across processes, but it is only supported by Unix-like operating systems. In order to construct and use a shared memory object in a parent process and a set of forked child processes, construct the object in the parent and fork as normal. The Balau Fork class provides a convenient API for forking. The shared memory object will be ready for use in the child processes without any further action. The first constructor is used for this.

			// The type of object being shared.
			struct A {
				int i;
				double d;

				A(int i_, double d_) : i(i_), d(d_) {}
			};

			// Construct the shared memory object before forking.
			MSharedMemoryObject<A> sharedA(1, 2.0);

			// Perform the fork. The child will not return.
			Fork::performFork([&sharedA] () { return runChildLogic(sharedA); }, true)
		

As previously discussed, use of the USharedMemoryObject class with forking will require subsequent calls to remap() in each child process before the object is usable. The equivalent code to the previous example using an instance of USharedMemoryObject is thus as follows.

			// Construct the shared memory object before forking.
			USharedMemoryObject<A> sharedA(1, 2.0);

			// Perform the fork. The child will not return.
			Fork::performFork(
				[&sharedA] () {
					sharedA.remap();
					return runChildLogic(sharedA);
				}
				, true
			)
		

Independent processes

Processes that are not related by forking may access the same shared memory object by communicating the name prefix to each process. A choice of constructors are available for this, which implement the Boost Interprocess create-only, create-or-open, open-only, and open-read-only options.

There are two possibilities for communicating the name prefix:

With the first solution, a name prefix is decided upon in advance or is algorithmically generated by the application. One solution to this when sharing an object between multiple instances of the same application is to construct a name prefix via the application's executable path. A helper function namePrefixFromAppPath() is available for this in the SharedMemoryUtils class. Using this solution, a set of shared memory object name prefixes can be created by appending predefined strings to the name prefix generated from the helper function.

Another solution is to pre-share a name prefix that can be guaranteed not to be used by other processes, either hard wired in the application (not recommended) or via the application's configuration/options.

The template constructors are used for creating/opening a shared memory object with a pre-shared or algorithmically generated name.

In order to use a peer-to-peer approach, the create-or-open constructor can be used.

			// Create the name prefix for the shared memory object.
			const std::string name = SharedMemoryUtils::namePrefixFromAppPath() + "_myObj";

			// Create or open the shared memory object with the name prefix.
			USharedMemoryObject<A> object(OpenOrCreate, name, 2, 4.0);
		

In order to use a manager-worker approach, the create-only constructor can be used in the manager process and the open-only constructor can be used in the worker processes. Due to the necessity of the queue existing for the worker processes, the manager process will need to create the queue before the workers attempt to open it.

			// Manager process..

			// Create the name prefix for the shared memory object.
			const std::string name = SharedMemoryUtils::namePrefixFromAppPath() + "_myObj";

			// Create the shared memory object.
			USharedMemoryObject<A> object(CreateOnly, name, 2, 4.0);

			///////////////////////////////////////////////////////////////////

			// Worker process..

			// Create a name prefix for the shared memory object.
			const std::string name = SharedMemoryUtils::namePrefixFromAppPath() + "_myObj";

			// Open the shared memory object.
			USharedMemoryObject<A> object(OpenOnly, name);