c++ - boost::interprocess 消息队列未删除
问题描述
使用 boost::interprocess 消息队列时,我遇到了删除队列的问题,希望有人可以为这种行为提供解释,或者纠正我的误解。我在 Linux RHEL7 机器上。我有两个进程,一个创建和提供队列,另一个打开消息队列并从中读取。为清楚起见,首先启动初始进程,然后是从队列中读取/删除消息的第二个进程。创造的,是create_only_t
。如果它已经存在,我希望它失败。然而,第一个队列的创建总是失败。它抛出的具体异常是File exists
.
当切换到open_or_create_t
队列时,它工作正常。由于没有正确清理它,因此我获取了此信息,因此我确保在尝试创建队列之前以及在该过程完成发送所有消息之后尝试删除队列。如果删除成功,我会记录。我的一个假设是,如果 remove 返回 true,则意味着它成功删除了队列。用于读取的 boost 文档remove
:“从系统中删除消息队列。出错时返回 false。”,我不确定是否可能是 true 只是意味着它已成功“尝试”删除它。在进一步查看另一个Boost Inprocess pdf后,它解释说:
如果共享内存不存在、文件已打开或文件仍是由其他进程映射的内存,则删除操作可能会失败并返回 false
无论哪种情况,我觉得如果队列总是返回 true,我会期望它被删除,这就是我目前的情况。仍然在尝试执行“create_t”消息队列时,它将继续失败,但“open_or_create_t”仍然有效。
我很难理解这种行为,因此我还尝试连续两次删除消息队列,然后再尝试初始化create_t
队列以查看第二个队列是否会失败/返回 false,但是两者都返回 true(这不是我根据文档所说的预期)。第一次删除应该成功意味着第二次删除应该失败,因为应该不再存在消息队列。
我附上了我的创建过程代码片段。我会注意到,这个错误是在没有运行“打开进程”的情况下发生的。
也许我错过了一些明显的东西,提前谢谢你。
try {
bool first_removal = remove(msg_queue_name);
if (first_removal) {
log_info("first removal - true"); // this log always prints
bool second_removal = remove(msg_queue_name);
if (second_removal ) {
log_info("removal was again true"); // this also always prints
} else {
log_info("second removal - false");
}
} else {
log_info("did not remove queue before creation");
}
log_info("attempting to initialize msg queue");
message_queue mq(ooc, msg_queue_name, max_num_msgs, max_msg_size); // this is where it will fail (File exists)
while(1) {
// insertion logic, but does not get here
}
} catch ( interprocess_exception& err ) {
log_error(err.what()); // File exists
bool removal_after_failure = remove(msg_queue_name);
if (removal_after_failure) {
log_info("Message queue was successfully removed"); // always logs here after every failure
} else {
log_warn("Message queue was NOT removed");
}
}
解决方案
它对我有用。
然后我恍然大悟。你大概是using namespace
。不。为此原因:
bool first_removal = remove(msg_queue_name);
这不会调用您期望的函数。::remove
它从 C 标准库调用。
只需限定您的通话:
bool first_removal = message_queue::remove(msg_queue_name);
措施
你可以做什么:
- 编写卫生代码
- 避免使用命名空间指令
- 避免 ADL 陷阱
- 使用警告(至少 -Wall -Wextra -pedantic)
- 使用短绒。见下文
- 检查您的假设(简单地进入调试器会告诉您发生了什么)
短绒?
例如clang-tidy
报道:
test.cpp|27 col 30| warning: implicit conversion 'int' -> bool [readability-implicit-bool-conversion]
|| bool first_removal = remove(msg_queue_name);
建议写:
bool first_removal = remove(msg_queue_name) != 0;
这让我知道有些事情可能是可疑的。
修复
稍后修复其中的几个并且代码运行
住在科利鲁
#include <boost/interprocess/ipc/message_queue.hpp>
#include <chrono>
#include <iostream>
namespace bip = boost::interprocess;
using bip::message_queue;
using bip::interprocess_exception;
using namespace std::chrono_literals;
using C = std::chrono::high_resolution_clock;
static constexpr char const* msg_queue_name = "my_mq";
static constexpr bip::open_or_create_t ooc;
static constexpr auto max_num_msgs = 10;
static constexpr auto max_msg_size = 10;
static auto log_impl = [start=C::now()](auto severity, auto const& ... args) {
std::clog << severity << " at " << std::fixed << (C::now()-start)/1.ms << "ms ";
(std::clog << ... << args) << std::endl;
};
static auto log_error = [](auto const& ... args) { log_impl("error", args...); };
static auto log_warn = [](auto const& ... args) { log_impl("warn", args...); };
static auto log_info = [](auto const& ... args) { log_impl("info", args...); };
int main() {
try {
bool first_removal = message_queue::remove(msg_queue_name);
if (first_removal) {
log_info("first removal - true"); // this log always prints
bool second_removal = message_queue::remove(msg_queue_name);
if (second_removal) {
log_info("removal was again true"); // this also always prints
} else {
log_info("second removal - false");
}
} else {
log_info("did not remove queue before creation");
}
log_info("attempting to initialize msg queue");
message_queue mq(
ooc, msg_queue_name, max_num_msgs,
max_msg_size); // this is where it will fail (File exists)
log_info("Start insertion");
} catch (interprocess_exception& err) {
log_error(err.what()); // File exists
bool removal_after_failure = message_queue::remove(msg_queue_name);
if (removal_after_failure) {
log_info("Message queue was successfully removed"); // always logs
// here after
// every failure
} else {
log_warn("Message queue was NOT removed");
}
}
}
在 Coliru 上打印:
info at 22.723521ms did not remove queue before creation
info at 22.879425ms attempting to initialize msg queue
error at 23.098989ms Function not implemented
warn at 23.153540ms Message queue was NOT removed
在我的系统上:
info at 0.148484ms first removal - true
info at 0.210316ms second removal - false
info at 0.232181ms attempting to initialize msg queue
info at 0.299645ms Start insertion
./sotest
info at 0.099407ms first removal - true
info at 0.173156ms second removal - false
info at 0.188026ms attempting to initialize msg queue
info at 0.257117ms Start insertion
当然现在你的逻辑可以大大简化:
int main() {
try {
bool removal = message_queue::remove(msg_queue_name);
log_info("attempting to initialize msg queue (removal:", removal, ")");
message_queue mq(
ooc, msg_queue_name, max_num_msgs,
max_msg_size); // this is where it will fail (File exists)
log_info("insertion");
} catch (interprocess_exception const& err) {
bool removal = message_queue::remove(msg_queue_name);
log_info(err.what(), " (removal:", removal, ")");
}
}
印刷
info at 0.462333ms attempting to initialize msg queue (removal:false)
info at 0.653085ms Function not implemented (removal:false)
或者
info at 0.097283ms attempting to initialize msg queue (removal:true)
info at 0.239138ms insertion
推荐阅读
- r - 按日期和项目计数汇总
- css - 如何使表单标签(几乎)永远不会换行?
- qt - QCharts 右侧的第二个 Y 轴
- flutter - 当 2 个代码并排时出现颤振条码扫描问题
- c# - 如何从 Visual Studio 中找到 c# 项目的类型?
- java - 服务内的线程 - Android 应用程序
- pact - Pact JS - 如何发送请求正文以更改状态?
- javascript - 每次我在它们上放一个可拖动的表格时,表格都会改变行的高度
- javascript - 使用 jQuery 打开一个链接会打开相关的应用程序,但是,继续此操作,会打开一个烦人的 about:blank 页面。我怎样才能阻止这个?
- curl - curl 从命令行工作,但不能在 shell 脚本中工作(curl:(6)无法解析主机:)