memory - boost消息队列创建的共享内存太小?
问题描述
我正在创建一个应用程序,其中多个进程通过增强消息队列进行通信。队列是使用消息队列构造函数创建的,因为
message_queue(open_or_create, name, max_num_msg, max_msg_size);
我对所有进程中的所有队列都使用 open_or_create,因为没有指定必须创建队列的顺序。
max_num_msg = 200
和max_msg_size = 500000
。
现在创建似乎一切都很好,但是在通过队列发送消息一段时间后,由于读取访问冲突,我遇到了突然的崩溃。做一些调试让我明白了do_send
在message_queue.hpp
哪里获得一个空的消息头来写消息的定义
//Insert the first free message in the priority queue
ipcdetail::msg_hdr_t<VoidPointer> &free_msg_hdr = p_hdr->queue_free_msg(priority);
//Sanity check, free msgs are always cleaned when received
BOOST_ASSERT(free_msg_hdr.priority == 0);
BOOST_ASSERT(free_msg_hdr.len == 0);
错误发生在free_msg_hdr.priority == 0
因为地址free_msg_hdr
不指向可读位置。
做更多的研究发现,在队列的创建中,
template<class VoidPointer>
inline message_queue_t<VoidPointer>::message_queue_t(open_or_create_t,
const char *name,
size_type max_num_msg,
size_type max_msg_size,
const permissions &perm)
//Create shared memory and execute functor atomically
: m_shmem(open_or_create,
name,
get_mem_size(max_msg_size, max_num_msg),
read_write,
static_cast<void*>(0),
//Prepare initialization functor
ipcdetail::msg_queue_initialization_func_t<VoidPointer>(max_num_msg, max_msg_size),
perm)
{}
创建的共享内存对象m_shmem
的大小太小,无法容纳 200 条大小为 500000 的消息。这解释了为什么崩溃有点不可预测,因为仍然有一小部分内存是可访问的,因此意外进入不可访问的内存需要一些时间部分。但是,我仍然不知道为什么会这样。查看函数get_mem_size(max_msg_size, max_num_msg)
它返回正确的大小,但创建后大小更小。如果我然后重新创建相同的队列,它通常会得到正确的大小,并且我永远不会遇到任何异常。如果有人知道为什么会发生这种情况,或者对如何进一步调试此问题提出建议,将不胜感激。
我可能应该提到,该应用程序是在 32 位的 Visual C++ 中编译并在 Windows 10 上运行。Windows 共享内存实现会导致这样的问题吗?
解决方案
当 boost 库创建消息队列时,它会请求一块共享内存来保存队列。我不确切知道它是如何工作的,也许它取决于操作系统的实现,但在 Windows 上,我可以在调试器中看到内存段的大小正在缓慢上升(连接调试器时非常缓慢,这就是我注意到的原因)而获得的共享内存用零填充。在我们的例子中,其他进程在此期间附加到消息队列,显然获得了共享内存的当前大小。但是,内存开头的队列头告诉它应该更大,因此第二个进程最终将访问它尚未映射到其地址空间的内存范围中的消息,从而产生读取访问冲突。
在我们的案例中,确保其他进程仅在我们确定队列已创建并因此我们的问题得到解决后才打开队列是相对容易的!
推荐阅读
- swift - Swift 结构和类
- c# - 如何使用 Web 服务或 WCF 服务创建 Windows Embedded Compact 7.0 应用程序开发?
- javascript - 如何在 w3 自动完成 https://www.w3schools.com/howto/howto_js_autocomplete.asp 给出的代码中提供 json 数据
- android - 在特定位置的范围内自动打开我的应用程序
- powershell - PowerShell - 对文件夹和子文件夹中的文件的操作
- python - Python中的省略号有什么用?
- php - 如何使用 where 子句从 Eloquent 模型中获取帐单地址?
- r - 插入刻度数天,标签数周
- python - python setup.py install 忽略 install_requires
- animation - 将网格视图切换到列表视图时的动画 - Flutter