The Boost C++ Libraries

Shared Memory

Shared memory is typically the fastest form of interprocess communication. It provides a memory area that is shared between processes. One process can write data to the area and another process can read it.

In Boost.Interprocess the class boost::interprocess::shared_memory_object is used to represent shared memory. Include the header file boost/interprocess/shared_memory_object.hpp to use this class.

Example 33.1. Creating shared memory
#include <boost/interprocess/shared_memory_object.hpp>
#include <iostream>

using namespace boost::interprocess;

int main()
{
  shared_memory_object shdmem{open_or_create, "Boost", read_write};
  shdmem.truncate(1024);
  std::cout << shdmem.get_name() << '\n';
  offset_t size;
  if (shdmem.get_size(size))
    std::cout << size << '\n';
}

The constructor of boost::interprocess::shared_memory_object expects three parameters. The first parameter specifies whether the shared memory should be created or just opened. Example 33.1 handles both cases. boost::interprocess::open_or_create will open shared memory if it already exists or create shared memory if it doesn’t.

Opening existing shared memory assumes that it has been created before. To uniquely identify shared memory, a name is assigned. That name is specified by the second parameter passed to the constructor of boost::interprocess::shared_memory_object.

The third parameter determines how a process can access shared memory. In Example 33.1, boost::interprocess::read_write says the process has read-write access.

After creating an object of type boost::interprocess::shared_memory_object, a corresponding shared memory block will exist within the operating system. The size of this memory area is initially 0. To use the area, call truncate(), passing in the size of the shared memory in bytes. In Example 33.1, the shared memory provides space for 1,024 bytes. truncate() can only be called if the shared memory has been opened with boost::interprocess::read_write. If not, an exception of type boost::interprocess::interprocess_exception is thrown. truncate() can be called repeatedly to adjust the size of the shared memory.

After creating shared memory, member functions such as get_name() and get_size() can be used to query the name and the size of the shared memory.

Because shared memory is used to exchange data between different processes, each process needs to map the shared memory into its address space. The class boost::interprocess::mapped_region is used to do this. It may come as a surprise that two classes (boost::interprocess::shared_memory_object and boost::interprocess::mapped_region) are needed to access shared memory. This is done so that the class boost::interprocess::mapped_region can also be used to map other objects into the address space of a process.

Example 33.2. Mapping shared memory into the address space of a process
#include <boost/interprocess/shared_memory_object.hpp>
#include <boost/interprocess/mapped_region.hpp>
#include <iostream>

using namespace boost::interprocess;

int main()
{
  shared_memory_object shdmem{open_or_create, "Boost", read_write};
  shdmem.truncate(1024);
  mapped_region region{shdmem, read_write};
  std::cout << std::hex << region.get_address() << '\n';
  std::cout << std::dec << region.get_size() << '\n';
  mapped_region region2{shdmem, read_only};
  std::cout << std::hex << region2.get_address() << '\n';
  std::cout << std::dec << region2.get_size() << '\n';
}

To use the class boost::interprocess::mapped_region, include the header file boost/interprocess/mapped_region.hpp. An object of type boost::interprocess::shared_memory_object must be passed as the first parameter to the constructor of boost::interprocess::mapped_region. The second parameter determines whether access to the memory area is read-only or read-write.

Example 33.2 creates two objects of type boost::interprocess::mapped_region. The shared memory named Boost is mapped twice into the address space of the process. The address and the size of the mapped memory area is written to standard output using the member functions get_address() and get_size(). get_size() returns 1024 in both cases, but the return value of get_address() is different for each object.

Note

Example 33.2, and some of the examples that follow, will cause a compiler error with Visual C++ 2013 and Boost 1.55.0. The bug is described in ticket 9332. This bug has been fixed in Boost 1.56.0.

Example 33.3. Writing and reading a number in shared memory
#include <boost/interprocess/shared_memory_object.hpp>
#include <boost/interprocess/mapped_region.hpp>
#include <iostream>

using namespace boost::interprocess;

int main()
{
  shared_memory_object shdmem{open_or_create, "Boost", read_write};
  shdmem.truncate(1024);
  mapped_region region{shdmem, read_write};
  int *i1 = static_cast<int*>(region.get_address());
  *i1 = 99;
  mapped_region region2{shdmem, read_only};
  int *i2 = static_cast<int*>(region2.get_address());
  std::cout << *i2 << '\n';
}

Example 33.3 uses the mapped memory area to write and read a number. region writes the number 99 to the beginning of the shared memory. region2 then reads the same location in shared memory and writes the number to the standard output stream. Even though region and region2 represent different memory areas within the process, as seen by the return values of get_address() in the previous example, the program prints 99 because both memory areas access the same underlying shared memory.

Example 33.4. Deleting shared memory
#include <boost/interprocess/shared_memory_object.hpp>
#include <iostream>

using namespace boost::interprocess;

int main()
{
  bool removed = shared_memory_object::remove("Boost");
  std::cout << std::boolalpha << removed << '\n';
}

To delete shared memory, boost::interprocess::shared_memory_object offers the static member function remove(), which takes the name of the shared memory to be deleted as a parameter (see Example 33.4).

Boost.Interprocess partially supports the RAII idiom through a class called boost::interprocess::remove_shared_memory_on_destroy. Its constructor expects the name of an existing shared memory. If an object of this class is destroyed, the shared memory is automatically deleted in the destructor.

The constructor of boost::interprocess::remove_shared_memory_on_destroy does not create or open the shared memory. Therefore, this class is not a typical representative of the RAII idiom.

If remove() is never called, the shared memory continues to exist even if the program terminates. Whether or not the shared memory is automatically deleted depends on the underlying operating system. Windows and many Unix operating systems, including Linux, automatically delete shared memory once the system is restarted.

Windows provides a special kind of shared memory that is automatically deleted once the last process using it has been terminated. Access the class boost::interprocess::windows_shared_memory, which is defined in boost/interprocess/windows_shared_memory.hpp, to use this kind of shared memory (see Example 33.5).

Example 33.5. Using Windows-specific shared memory
#include <boost/interprocess/windows_shared_memory.hpp>
#include <boost/interprocess/mapped_region.hpp>
#include <iostream>

using namespace boost::interprocess;

int main()
{
  windows_shared_memory shdmem{open_or_create, "Boost", read_write, 1024};
  mapped_region region{shdmem, read_write};
  int *i1 = static_cast<int*>(region.get_address());
  *i1 = 99;
  mapped_region region2{shdmem, read_only};
  int *i2 = static_cast<int*>(region2.get_address());
  std::cout << *i2 << '\n';
}

boost::interprocess::windows_shared_memory does not provide a member function truncate(). Instead, the size of the shared memory needs to be passed as the fourth parameter to the constructor.

Even though the class boost::interprocess::windows_shared_memory is not portable and can only be used on Windows, it is useful when data needs to be exchanged with an existing Windows program that uses this special kind of shared memory.