Boost.Interprocess 使用 Windows COM 库实现某些功能,并使用并发模型COINIT_APARTMENTTHREADED
对其进行初始化。如果调用线程已为其他并发模型初始化了 COM 库,Boost.Interprocess 将优雅地处理这种情况,并使用已初始化模型的 COM 调用。如果由于某种原因,您希望 Boost.Interprocess 使用其他模型初始化 COM 库,请在包含 Boost.Interprocess 之前定义宏 BOOST_INTERPROCESS_WINDOWS_COINIT_MODEL
为以下值之一:
COINIT_APARTMENTTHREADED_BIPC
COINIT_MULTITHREADED_BIPC
COINIT_DISABLE_OLE1DDE_BIPC
COINIT_SPEED_OVER_MEMORY_BIPC
共享内存(shared_memory_object
)在 Windows 中使用内存映射文件实现,这些文件放置在共享文档文件夹中的共享目录中(SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders\Common AppData
)。此目录名称是通过会话管理器的注册表值获得的最后一次启动时间。自 Boost 1.74 起,此行为为默认行为。
旧版 Boost.Interprocess(直到 Boost 1.48)使用 COM 调用(通过宏 BOOST_INTERPROCESS_BOOTSTAMP_IS_LASTBOOTUPTIME
),但该时间戳在虚拟机和时间调整中不可靠。直到(Boost 1.74)的后续版本使用 EventLog 启动事件作为时间戳,但一些用户发现,如果系统运行时间较长,则 Event Log 中可能缺少此事件。您可以通过定义 BOOST_INTERPROCESS_BOOTSTAMP_IS_EVENTLOG_BASED 来强制使用基于 Event Log 的时间戳。
在任何错误情况下(未定义共享文档文件夹或无法获得启动时间),库都会抛出错误。您仍然可以通过定义您自己的目录作为共享目录来使用 Boost.Interprocess。当您的共享目录是编译时常量时,在使用库时定义 BOOST_INTERPROCESS_SHARED_DIR_PATH
(以及 Windows 系统中的 BOOST_INTERPROCESS_SHARED_DIR_WPATH),该路径将用于放置共享内存文件。当您必须在运行时确定共享目录时,定义 BOOST_INTERPROCESS_SHARED_DIR_FUNC
并实现以下函数:
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); } } }
如果定义了 BOOST_USE_WINDOWS_H
,则包含 <windows.h> 和其他 Windows SDK 文件,否则库将声明所需的函数和结构以减少包含这些大型头文件的的影响。
在没有 POSIX 共享内存支持的系统上,共享内存对象实现为内存映射文件,使用放置在“/tmp”中的目录,该目录可以包含(如果定义了 BOOST_INTERPROCESS_HAS_KERNEL_BOOTTIME
)最后一次启动时间(如果操作系统支持)。与 Windows 一样,在获取此目录出现任何错误的情况下,库都会抛出错误。当您的共享目录是编译时常量时,在使用库时定义 BOOST_INTERPROCESS_SHARED_DIR_PATH
,该路径将用于放置共享内存文件。当您必须在运行时确定共享目录时,定义 BOOST_INTERPROCESS_SHARED_DIR_FUNC
并实现该函数:
namespace boost { namespace interprocess { namespace ipcdetail { void get_shared_dir(std::string &shared_dir); } } }
已提交的地址空间是内核可能必须提供的虚拟内存总量(交换空间或物理内存/RAM),如果所有应用程序都决定访问它们从内核请求的所有内存,则会发生这种情况。默认情况下,Linux 允许进程提交比系统中可用的虚拟内存更多的虚拟内存。如果未访问该内存,则实际上不会使用物理内存 + 交换空间。
这种行为的原因是 Linux 尝试优化 fork 进程的内存使用;fork() 创建进程空间的完整副本,但是使用内存超额提交,在此新的 fork 实例中,只有已被写入的页面才需要内核分配。如果应用程序访问的内存超过可用内存,则内核必须以硬方式释放内存:OOM(内存不足)杀手选择一些进程以杀死以恢复内存。
Boost.Interprocess 无法更改此行为,并且用户在访问共享内存时可能会遇到 OOM 杀手。根据 内核文档,Linux 内核支持几种内存超额提交模式。如果您在应用程序中需要非终止保证,则应更改此内存超额提交行为。
从 FreeBSD 11 开始,声明宏 _POSIX_THREAD_PROCESS_SHARED。但是,默认行为与 Linux 上的行为不同。如果您想使用此功能,根据 libthr(3) 的手册页,您应该检查 sysctl 的 kern.ipc.umtx_vnode_persistent
如果您希望映射文件在最后一个句柄关闭后仍然可用,请将此变量设置为 1。
Boost.Interprocess 在 macOS 中使用 POSIX 共享内存来实现共享内存类。
但是,沙盒应用程序无法使用 System V (XSI) 信号量和 POSIX 信号量,并且默认情况下无法使用共享内存。但是,通过指定请求应用程序组成员资格的权利,应用程序可以使用这些技术与该应用程序组的其他成员进行通信。
请参阅 Apple 文档 了解有关如何在沙盒应用程序上使用进程间通信的限制和指南。
许多人贡献了想法和修订,所以这是感谢他们的地方。
<boost/interprocess/containers/*.hpp>
头文件。它们是 2011 年 Boost.Container 的原始来源,但不再维护。作为长期过渡,Boost.Interprocess 保留了这些头文件以保持兼容性。它们将在未来的 Boost 版本中删除。segment_manager
现在使用新的实现,支持超对齐类型并修复了一些现有错误。您可以在包含 Boost.Interprocess 头文件之前,通过将 BOOST_INTERPROCESS_SEGMENT_MANAGER_ABI
定义为 1
来获得 Boost 1.87 之前的 ABI。interprocess::ipcdetail::intermodule_singleton
在 MinGW 上无法工作").
浮点数精度问题 导致
get_current_process_creation_time 导致
intermodule_singleton` 失败").
offset_ptr
添加了 natvis 定义。非常感谢 Braden Ganetsky。unordered_map_index
类。TimedLockable
要求,条件变量实现了 wait_until/wait_for
操作。boost::date_time::ptime
、std::time_point
或boost::chrono::time_point
。wchar_t
API支持。以下类已更新为支持wchar_t
名称file_mapping
managed_mapped_file
managed_shared_memory
managed_windows_shared_memory
shared_memory_object
windows_shared_memory_object
file_lock
named_condition
named_condition_any
named_mutex
named_recursive_mutex
named_semaphore
named_sharable_mutex
named_upgradable_mutex
message_queue
BOOST_INTERPROCESS_FORCE_NATIVE_EMULATION
宏选项,用于禁用对进程共享同步原语使用通用模拟代码,而不是使用原生POSIX或Winapi函数。BOOST_INTERPROCESS_BOOTSTAMP_IS_SESSION_MANAGER_BASED
现在是默认值。您可以通过定义BOOST_INTERPROCESS_BOOTSTAMP_IS_EVENTLOG_BASED
来获得Boost 1.73之前的行为。旧的和已损坏的Boost 1.54之前的行为(BOOST_INTERPROCESS_BOOTSTAMP_IS_LASTBOOTUPTIME
)不再可用。BOOST_INTERPROCESS_BOOTSTAMP_IS_SESSION_MANAGER_BASED
。此选项从与会话管理器关联的注册表值派生用于命名放置共享内存的文件夹的唯一bootstamp。此选项仅在Vista及更高版本的系统上有效,并且可能比默认版本更稳定。offset_ptr
性能并消除了任何未定义的行为。无需针对不同的编译器进行特殊处理。unique_ptr
,现在将boost::interprocess::unique_ptr转发到来自Boost.Move的通用boost::movelib::unique_ptr
类。此实现更接近标准std::unique_ptr
实现,并且维护得更好。BOOST_INTERPROCESS_MSG_QUEUE_CIRCULAR_INDEX
选项完全损坏,因此需要进行 ABI 破坏性变更才能实现正常的功能。BOOST_INTERPROCESS_SHARED_DIR_PATH
选项,用于定义当共享内存对象实现为内存映射文件时使用的共享目录。BOOST_USE_WINDOWS_H
的支持。定义此宏后,Interprocess 不会声明使用的 Windows API 函数和类型,而是包含所有需要的 Windows SDK 头文件,并使用 Windows SDK 声明的类型和函数。::boost:interprocess:windows_shared_memory
添加了 get_size
。LastBootupTime
在时间同步和休眠状态下不稳定,实际上不可用。如果您确实需要获得 Boost 1.54 之前的行为,请从命令行或 detail/workaround.hpp
定义 BOOST_INTERPROCESS_BOOTSTAMP_IS_LASTBOOTUPTIME
。mapped_region
中添加了 shrink_by
和 advise
函数。message_queue
(旧的行为使用有序数组,导致过度复制)。这应该会大大提高性能,但会破坏 ABI。可以通过在 boost/interprocess/detail/workaround.hpp
中取消定义宏 BOOST_INTERPROCESS_MSG_QUEUE_CIRCULAR_INDEX
来使用旧的行为/ABI。message_queue
的插入时间,避免了常见情况下的优先级搜索(数组和循环缓冲区配置)。interproces_sharable_mutex
和 interproces_condition_any
。offset_ptr
的性能。mapped_region::flush
添加了同步和异步刷新。mapped_region
中删除了 get_offset
方法,因为它没有实际用途,并且 m_offset
成员也不用于其他任何用途。managed_shared_memory
中删除了 flush
,因为它根据 POSIX 未指定:“msync() 对共享内存对象或类型化内存对象的影响未指定” 。mapped_region::flush
启动磁盘刷新,但不保证在返回时已完成,因为它不可移植。semaphore
和 named_semaphore
现在使用原子操作实现了更高效的实现。BOOST_INTERPROCESS_FORCE_GENERIC_EMULATION
宏选项,强制使用泛型模拟代码来实现进程共享同步原语,而不是本地 POSIX 函数。boost::posix_time::pos_inf
值现在对于定时函数的可移植性得到处理。iterator
改为 const_iterator
。void
flat_map::erase()
函数错误的返回类型。mapped_region
添加了用于创建它的模式。shared_ptr
可移动且支持别名。shared_ptr
、weak_ptr
和 unique_ptr
的定义和构造。在文档中添加了这些智能指针的解释和示例。pointer
定义为智能指针的分配器时,尽可能使用原始指针。这提高了性能并缩短了编译时间。named_mutex
和 named_semaphore
。 named_condition
已相应更改以支持与 named_mutex
的互操作性。mapped_region
的 bug,当提供映射地址但区域映射到另一个地址时。aligned_allocate
和 allocate_many
函数。get_instance_name
、get_instance_length
和 get_instance_type
函数。rbtree_best_fit
中次优缓冲区扩展的 bug。vector
中的内存泄漏。segment_manager
以避免与模板实例化相关的代码膨胀。deque::clear()
和 deque::erase()
的 bug,它们被声明为私有的。deque::erase()
的 bug。感谢 Steve LoBasso。atomic_dec32()
的 bug。感谢 Glenn Schrader。offset_ptr
指针。managed_mapped_file
创建的文件的压缩率而有用。boost::has_trivial_destructor
。此优化避免调用具有平凡析构函数的元素的析构函数。has_trivial_destructor_after_move
特性。如果元素已被移动(许多可移动类型的情况),此优化将避免调用具有平凡析构函数的元素的析构函数。此技巧由Howard Hinnant提供。deallocate_free_chunks()
)以手动从节点分配器中释放完全空闲的块。multiset
和multimap
类中实现了N1780提案以解决LWG问题233:关联容器中的插入提示。shared_memory_object.hpp
头文件,而不是shared memory.hpp
。mode_t
类型。mapped_region
构造函数不再需要从memory_mappable派生的类,但类必须满足MemoryMappable概念。一些关于C++编程语言、C++内部机制、共享内存、分配器和容器的有用参考,用于设计Boost.Interprocess。
我有一些想要实现的Interprocess功能,以及一些可以改进的Boost.Interprocess代码。让我们看看一些想法
共享互斥锁和共享条件的Win32版本基于“自旋和等待”原子指令。这会导致性能低下,并且不会管理任何诸如优先级反转之类的问题。我们需要线程专家在这方面提供非常重要的帮助。我不确定这是否可以在用户级软件中实现。基于Posix的实现使用PTHREAD_PROCESS_SHARED属性将互斥锁放置在共享内存中,因此没有此类问题。我不知道有任何模拟Win32的PTHREAD_PROCESS_SHARED属性的实现。我们应该能够在内存映射文件中构造这些原语,以便我们可以像使用POSIX原语一样获得文件系统持久性。
目前Interprocess只允许char作为基本命名对象的名称。但是,一些操作系统使用wchar_t作为资源名称(例如,映射文件)。将来,Interprocess应该尝试提供一个可移植的窄/宽字符接口。为此,使用boost wstring <-> string转换实用程序以可移植的方式转换资源名称(转义可能与操作系统名称冲突的字符)将很有用。使用boost::filesystem路径来避免操作系统特定问题也很有趣。
Boost.Interprocess没有为共享内存和同步对象定义安全属性。标准C++也忽略了文件的安全属性,因此添加安全属性需要一些认真工作。
Boost.Interprocess提供了一个基于Boost.Interprocess原语(如互斥锁和条件)的进程共享消息队列。我想开发更多机制,例如面向流的命名FIFO,以便我们可以将其与iostream接口包装器一起使用(我们可以模拟Unix管道)。
C++需要更复杂的机制,在C++中拥有面向流和数据报的面向PF_UNIX的机制将会很好。对于非常快速的进程间远程调用,Solaris doors是为C++实现的一个有趣的替代方案。但是实现类似PF_UNIX的套接字和门的这项工作将是巨大的(并且在用户级库中可能很困难)。有没有网络专家志愿者?