Boost C++ Libraries

...one of the most highly regarded and expertly designed C++ library projects in the world. Herb Sutter and Andrei Alexandrescu, C++ Coding Standards

PrevUpHomeNext

Acknowledgements, notes and links

Notes for Windows users
Notes for Linux users
Notes for FreeBSD users
Notes for MacOs users
Thanks to...
Release Notes
Books and interesting links
Future improvements...

Boost.Interprocess uses the Windows COM library to implement some features and initializes it with concurrency model COINIT_APARTMENTTHREADED. If the COM library was already initialized by the calling thread for another concurrency model, Boost.Interprocess handles this gracefully and uses COM calls for the already initialized model. If for some reason, you want Boost.Interprocess to initialize the COM library with another model, define the macro BOOST_INTERPROCESS_WINDOWS_COINIT_MODEL before including Boost.Interprocess to one of these values:

  • COINIT_APARTMENTTHREADED_BIPC
  • COINIT_MULTITHREADED_BIPC
  • COINIT_DISABLE_OLE1DDE_BIPC
  • COINIT_SPEED_OVER_MEMORY_BIPC

Shared memory (shared_memory_object) is implemented in Windows using memory mapped files, placed in a shared directory in the shared documents folder (SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders\Common AppData). This directory name is the last bootup time obtained via Registry values of the Session Manager. This behaviour is the default since Boost 1.74.

Old Boost.Interprocess versions (until Boost 1.48 ) used COM calls (via macro BOOST_INTERPROCESS_BOOTSTAMP_IS_LASTBOOTUPTIME) but that timestamp was unreliable in Virtual Machines and time adjustements. Next versions until (Boost 1.74) used EventLog startup event as timestamp, but several users discovered this event could be absent in the Event Log if the system was up for a long time. You can force this Event Log based timestamp defining BOOST_INTERPROCESS_BOOTSTAMP_IS_EVENTLOG_BASED.

In any error case (shared documents folder is not defined or bootup time could not be obtained), the library throws an error. You still can use Boost.Interprocess defining your own directory as the shared directory. When your shared directory is a compile-time constant, define BOOST_INTERPROCESS_SHARED_DIR_PATH (and BOOST_INTERPROCESS_SHARED_DIR_WPATH in Windows systems) when using the library and that path will be used to place shared memory files. When you have to determine the shared directory at runtime, define BOOST_INTERPROCESS_SHARED_DIR_FUNC and implement the following functions

namespace boost {
    namespace interprocess {
        namespace ipcdetail {
            void get_shared_dir(std::string &shared_dir);
            //wstring overload is only needed for Windows systems
            void get_shared_dir(std::wstring &shared_dir);
        }
    }
}

If BOOST_USE_WINDOWS_H is defined, <windows.h> and other windows SDK files are included, otherwise the library declares needed functions and structures to reduce the impact of including those heavy headers.

On systems without POSIX shared memory support, shared memory objects are implemented as memory mapped files, using a directory placed in "/tmp" that can include (if BOOST_INTERPROCESS_HAS_KERNEL_BOOTTIME is defined) the last bootup time (if the OS supports it). As in Windows, in any error case obtaining this directory the library throws an error . When your shared directory is a compile-time constant, define BOOST_INTERPROCESS_SHARED_DIR_PATH when using the library and that path will be used to place shared memory files. When you have to determine the shared directory at runtime, define BOOST_INTERPROCESS_SHARED_DIR_FUNC and implement the function

namespace boost {
    namespace interprocess {
        namespace ipcdetail {
            void get_shared_dir(std::string &shared_dir);
        }
    }
}

The committed address space is the total amount of virtual memory (swap or physical memory/RAM) that the kernel might have to supply if all applications decide to access all of the memory they've requested from the kernel. By default, Linux allows processes to commit more virtual memory than available in the system. If that memory is not accessed, no physical memory + swap is actually used.

The reason for this behaviour is that Linux tries to optimize memory usage on forked processes; fork() creates a full copy of the process space, but with overcommitted memory, in this new forked instance only pages which have been written to actually need to be allocated by the kernel. If applications access more memory than available, then the kernel must free memory in the hard way: the OOM (Out Of Memory)-killer picks some processes to kill in order to recover memory.

Boost.Interprocess has no way to change this behaviour and users might suffer the OOM-killer when accessing shared memory. According to the Kernel documentation, the Linux kernel supports several overcommit modes. If you need non-kill guarantees in your application, you should change this overcommit behaviour.

Starting from FreeBSD 11, declares the macro _POSIX_THREAD_PROCESS_SHARED. However, the default behavior is different from the one on Linux. If you want to use this feature, according to the man page of libthr(3), you should check sysctl's kern.ipc.umtx_vnode_persistent:

  • kern.ipc.umtx_vnode_persistent: By default, a shared lock backed by a mapped file in memory is automatically destroyed on the last unmap of the corresponding file's page, which is allowed by POSIX. Setting the sysctl to 1 makes such a shared lock object persist until the vnode is recycled by the Virtual File System. Note that in case file is not opened and not mapped, the kernel might recycle it at any moment, making this sysctl less useful than it sounds.

If you want mapped files to remain useful after the last handle is closed, set this variable to 1.

Boost.Interprocess uses POSIX shared memory in MacOS to implement shared memory classes in MacOS.

But sandboxed apps cannot use System V (XSI) semaphores and POSIX semaphores and shared memory can't be used by default. However, by specifying an entitlement that requests membership in an application group, an app can use these technologies to communicate with other members of that application group.

Please see Apple documentation for limitations and guide on how to use interprocess communications on sandboxed applications.

Many people have contributed with ideas and revisions, so this is the place to thank them:

  • Thanks to all people who have shown interest in the library and have downloaded and tested the snapshots.
  • Thanks to Francis Andre and Anders Hybertz for their ideas and suggestions. Many of them are not implemented yet but I hope to include them when library gets some stability.
  • Thanks to Matt Doyle, Steve LoBasso, Glenn Schrader, Hiang Swee Chiang, Phil Endecott, Rene Rivera, Harold Pirtle, Paul Ryan, Shumin Wu, Michal Wozniak, Peter Johnson, Alex Ott, Shane Guillory, Steven Wooding and Kim Barrett for their bug fixes and library testing.
  • Thanks to Martin Adrian who suggested the use of Interprocess framework for user defined buffers.
  • Thanks to Synge Todo for his boostbook-doxygen patch to improve Interprocess documentation.
  • Thanks to Olaf Krzikalla for his Intrusive library. I have taken some ideas to improve red black tree implementation from his library.
  • Thanks to Daniel James for his unordered_map/set family and his help with allocators. His great unordered implementation has been a reference to design exception safe containers.
  • Thanks to Howard Hinnant for his amazing help, specially explaining allocator swapping, move semantics and for developing upgradable mutex and lock transfer features.
  • Thanks to Pavel Vozenilek for his continuous review process, suggestions, code and help. He is the major supporter of Interprocess library. The library has grown with his many and great advices.
  • And finally, thank you to all Boosters. Long live to C++!
  • Fixed bugs:
    • #7156 ("interprocess buffer streams leak memory on construction"]).
    • #7164 ("Two potential bugs with b::int::vector of b::i::weak_ptr"]).
    • #7860 ("smart_ptr's yield_k and spinlock utilities can improve spinlock-based sychronization primitives"]).
    • #8277 ("docs for named_mutex erroneously refer to interprocess_mutex"]).
    • #8976 ("shared_ptr fails to compile if used with a scoped_allocator"]).
    • #9008 ("conditions variables fast enough only when opening a multiprocess browser"]).
    • #9065 ("atomic_cas32 inline assembly wrong on ppc32"]).
    • #9073 ("Conflict names 'realloc'"]).
  • Added support for platform-specific flags to mapped_region (ticket #8030)
  • Fixed bugs:
  • ABI breaking: Changed bootstamp function in Windows to use EventLog service start time as system bootup time. Previously used LastBootupTime from WMI was unstable with time synchronization and hibernation and unusable in practice. If you really need to obtain pre Boost 1.54 behaviour define BOOST_INTERPROCESS_BOOTSTAMP_IS_LASTBOOTUPTIME from command line or detail/workaround.hpp.
  • Fixed GCC -Wshadow warnings.
  • Experimental multiple allocation interface improved and changed again. Still unstable.
  • Replaced deprecated BOOST_NO_XXXX with newer BOOST_NO_CXX11_XXX macros.
  • ABI breaking: changed node pool allocators internals for improved efficiency.
  • Fixed bug #7795.
  • Added shrink_by and advise functions in mapped_region.
  • ABI breaking: Reimplemented message_queue with a circular buffer index (the old behavior used an ordered array, leading to excessive copies). This should greatly increase performance but breaks ABI. Old behaviour/ABI can be used undefining macro BOOST_INTERPROCESS_MSG_QUEUE_CIRCULAR_INDEX in boost/interprocess/detail/workaround.hpp
  • Improved message_queue insertion time avoiding priority search for common cases (both array and circular buffer configurations).
  • Implemented interproces_sharable_mutex and interproces_condition_any.
  • Improved offset_ptr performance.
  • Added integer overflow checks.
  • Fixed bugs #3750, #6727, #6648,
  • Shared memory in windows has again kernel persistence: kernel bootstamp and WMI has received some fixes and optimizations. This causes incompatibility with Boost 1.48 and 1.49 but the user can comment #define BOOST_INTERPROCESS_HAS_KERNEL_BOOTTIME in the windows configuration part to get Boost 1.48 & Boost 1.49 behaviour.
  • Fixed bugs #2796, #4031, #4251, #4452, #4895, #5077, #5120, #5123, #5230, #5197, #5287, #5294, #5306, #5308, #5392, #5409,
  • Added support to customize offset_ptr and allow creating custom managed segments that might be shared between 32 and 64 bit processes.
  • Shared memory in windows has again filesystem lifetime: kernel bootstamp and WMI use to get a reliable timestamp was causing a lot of trouble.
  • Support for POSIX shared memory in Mac OS.
  • ABI breaking: Generic semaphore and named_semaphore now implemented more efficiently with atomic operations.
  • More robust file opening in Windows platforms with active Anti-virus software.
  • Windows shared memory is created in Shared Documents folder so that it can be shared between services and processes
  • Fixed bugs #2967, #2973, #2992, #3138, #3166, #3205.
  • Added experimental stable_vector container.
  • shared_memory_object::remove has now POSIX unlink semantics and file_mapping::remove was added to obtain POSIX unlink semantics with mapped files.
  • Shared memory in windows has now kernel lifetime instead of filesystem lifetime: shared memory will disappear when the system reboots.
  • Updated move semantics.
  • Fixed bugs #2722, #2729, #2766, #1390, #2589,
  • Updated documentation to show rvalue-references funcions instead of emulation functions.
  • More non-copyable classes are now movable.
  • Move-constructor and assignments now leave moved object in default-constructed state instead of just swapping contents.
  • Several bugfixes ( #2391, #2431, #1390, #2570, #2528.
  • Containers can be used now in recursive types.
  • Added BOOST_INTERPROCESS_FORCE_GENERIC_EMULATION macro option to force the use of generic emulation code for process-shared synchronization primitives instead of native POSIX functions.
  • Added placement insertion members to containers
  • boost::posix_time::pos_inf value is now handled portably for timed functions.
  • Update some function parameters from iterator to const_iterator in containers to keep up with the draft of the next standard.
  • Documentation fixes.
  • Added anonymous shared memory for UNIX systems.
  • Fixed erroneous void return types from flat_map::erase() functions.
  • Fixed missing move semantics on managed memory classes.
  • Added copy_on_write and open_read_only options for shared memory and mapped file managed classes.
  • ABI breaking: Added to mapped_region the mode used to create it.
  • Corrected instantiation errors in void allocators.
  • shared_ptr is movable and supports aliasing.
  • Added auxiliary utilities to ease the definition and construction of shared_ptr, weak_ptr and unique_ptr. Added explanations and examples of these smart pointers in the documentation.
  • Optimized vector:
    • 1) Now works with raw pointers as much as possible when using allocators defining pointer as an smart pointer. This increases performance and improves compilation times.
    • 2) A bit of metaprogramming to avoid using move_iterator when the type has trivial copy constructor or assignment and improve performance.
    • 3) Changed custom algorithms with standard ones to take advantage of optimized standard algorithms.
    • 4) Removed unused code.
  • ABI breaking: Containers don't derive from allocators, to avoid problems with allocators that might define virtual functions with the same names as container member functions. That would convert container functions in virtual functions and might disallow some of them if the returned type does not lead to a covariant return. Allocators are now stored as base classes of internal structs.
  • Implemented named_mutex and named_semaphore with POSIX named semaphores in systems supporting that option. named_condition has been accordingly changed to support interoperability with named_mutex.
  • Reduced template bloat for node and adaptive allocators extracting node implementation to a class that only depends on the memory algorithm, instead of the segment manager + node size + node number...
  • Fixed bug in mapped_region in UNIX when mapping address was provided but the region was mapped in another address.
  • Added aligned_allocate and allocate_many functions to managed memory segments.
  • Improved documentation about managed memory segments.
  • Boost.Interprocess containers are now documented in the Reference section.
  • Correction of typos and documentation errors.
  • Added get_instance_name, get_instance_length and get_instance_type functions to managed memory segments.
  • Corrected suboptimal buffer expansion bug in rbtree_best_fit.
  • Added iteration of named and unique objects in a segment manager.
  • Fixed leak in vector.
  • Added support for Solaris.
  • Optimized segment_manager to avoid code bloat associated with templated instantiations.
  • Fixed bug for UNIX: No slash ('/') was being added as the first character for shared memory names, leading to errors in some UNIX systems.
  • Fixed bug in VC-8.0: Broken function inlining in core offset_ptr functions.
  • Code examples changed to use new BoostBook code import features.
  • Added aligned memory allocation function to memory algorithms.
  • Fixed bug in deque::clear() and deque::erase(), they were declared private.
  • Fixed bug in deque::erase(). Thanks to Steve LoBasso.
  • Fixed bug in atomic_dec32(). Thanks to Glenn Schrader.
  • Improved (multi)map/(multi)set constructors taking iterators. Now those have linear time if the iterator range is already sorted.
  • ABI breaking: (multi)map/(multi)set now reduce their node size. The color bit is embedded in the parent pointer. Now, the size of a node is the size of 3 pointers in most systems. This optimization is activated for raw and offset_ptr pointers.
  • (multi)map/(multi)set now reuse memory from old nodes in the assignment operator.
  • ABI breaking: Implemented node-containers based on intrusive containers. This saves code size, since many instantiations share the same algorithms.
  • Corrected code to be compilable with Visual C++ 8.0.
  • Added function to zero free memory in memory algorithms and the segment manager. This function is useful for security reasons and to improve compression ratios for files created with managed_mapped_file.
  • Added support for intrusive index types in managed memory segments. Intrusive indexes save extra memory allocations to allocate the index since with just one allocation, we allocate room for the value, the name and the hook to insert the object in the index.
  • Created new index type: iset_index. It's an index based on an intrusive set (rb-tree).
  • Created new index type: iunordered_set_index. It's an index based on a pseudo-intrusive unordered set (hash table).
  • ABI breaking: The intrusive index iset_index is now the default index type.
  • Optimized vector to take advantage of boost::has_trivial_destructor. This optimization avoids calling destructors of elements that have a trivial destructor.
  • Optimized vector to take advantage of has_trivial_destructor_after_move trait. This optimization avoids calling destructors of elements that have a trivial destructor if the element has been moved (which is the case of many movable types). This trick was provided by Howard Hinnant.
  • Added security check to avoid integer overflow bug in allocators and named construction functions.
  • Added alignment checks to forward and backwards expansion functions.
  • Fixed bug in atomic functions for PPC.
  • Fixed race-condition error when creating and opening a managed segment.
  • Added adaptive pools.
  • Source breaking: Changed node allocators' template parameter order to make them easier to use.
  • Added support for native windows shared memory.
  • Added more tests.
  • Corrected the presence of private functions in the reference section.
  • Added function (deallocate_free_chunks()) to manually deallocate completely free chunks from node allocators.
  • Implemented N1780 proposal to LWG issue 233: Insertion hints in associative containers in interprocess multiset and multimap classes.
  • Source breaking: A shared memory object is now used including shared_memory_object.hpp header instead of shared memory.hpp.
  • ABI breaking: Changed global mutex when initializing managed shared memory and memory mapped files. This change tries to minimize deadlocks.
  • Source breaking: Changed shared memory, memory mapped files and mapped region's open mode to a single mode_t type.
  • Added extra WIN32_LEAN_AND_MEAN before including DateTime headers to avoid socket redefinition errors when using Interprocess and Asio in windows.
  • ABI breaking: mapped_region constructor no longer requires classes derived from memory_mappable, but classes must fulfill the MemoryMappable concept.
  • Added in-place reallocation capabilities to basic_string.
  • ABI breaking: Reimplemented and optimized small string optimization. The narrow string class has zero byte overhead with an internal 11 byte buffer in 32 systems!
  • Added move semantics to containers. Improves performance when using containers of containers.
  • ABI breaking: End nodes of node containers (list, slist, map/set) are now embedded in the containers instead of allocated using the allocator. This allows no-throw move-constructors and improves performance.
  • ABI breaking: slist and list containers now have constant-time size() function. The size of the container is added as a member.

Some useful references about the C++ programming language, C++ internals, shared memory, allocators and containers used to design Boost.Interprocess.

  • Great book about multithreading, and POSIX: "Programming with Posix Threads", David R. Butenhof
  • The UNIX inter-process bible: "UNIX Network Programming, Volume 2: Interprocess Communications", W. Richard Stevens
  • Current STL allocator issues: "Effective STL", Scott Meyers
  • My C++ bible: "Thinking in C++, Volume 1 & 2", Bruce Eckel and Chuck Allison
  • The book every C++ programmer should read: "Inside the C++ Object Model", Stanley B. Lippman
  • A must-read: "ISO/IEC TR 18015: Technical Report on C++ Performance", ISO WG21-SC22 members.

There are some Interprocess features that I would like to implement and some Boost.Interprocess code that can be much better. Let's see some ideas:

Win32 version of shared mutexes and shared conditions are based on "spin and wait" atomic instructions. This leads to poor performance and does not manage any issues like priority inversions. We would need very serious help from threading experts on this. And I'm not sure that this can be achieved in user-level software. Posix based implementations use PTHREAD_PROCESS_SHARED attribute to place mutexes in shared memory, so there are no such problems. I'm not aware of any implementation that simulates PTHREAD_PROCESS_SHARED attribute for Win32. We should be able to construct these primitives in memory mapped files, so that we can get filesystem persistence just like with POSIX primitives.

Currently Interprocess only allows char based names for basic named objects. However, several operating systems use wchar_t names for resources (mapped files, for example). In the future Interprocess should try to present a portable narrow/wide char interface. To do this, it would be useful to have a boost wstring <-> string conversion utilities to translate resource names (escaping needed characters that can conflict with OS names) in a portable way. It would be interesting also the use of boost::filesystem paths to avoid operating system specific issues.

Boost.Interprocess does not define security attributes for shared memory and synchronization objects. Standard C++ also ignores security attributes with files so adding security attributes would require some serious work.

Boost.Interprocess offers a process-shared message queue based on Boost.Interprocess primitives like mutexes and conditions. I would want to develop more mechanisms, like stream-oriented named fifo so that we can use it with a iostream-interface wrapper (we can imitate Unix pipes).

C++ needs more complex mechanisms and it would be nice to have a stream and datagram oriented PF_UNIX-like mechanism in C++. And for very fast inter-process remote calls Solaris doors is an interesting alternative to implement for C++. But the work to implement PF_UNIX-like sockets and doors would be huge (and it might be difficult in a user-level library). Any network expert volunteer?


PrevUpHomeNext