首页 > 解决方案 > 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");
    }
  }

标签: c++boostmessage-queueboost-interprocess

解决方案


它对我有用。

然后我恍然大悟。你大概是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

推荐阅读