boost::interprocess 消息队列未删除

boost::interprocess message queue not removing

使用boost::interprocess 消息队列,我运行 遇到删除队列的问题,希望有人能对此行为提供解释,或纠正我的误解。 我在 Linux RHEL7 机器上。我有两个进程,一个创建并提供队列,另一个打开消息队列并从中读取。为清楚起见,首先启动初始进程,然后再启动队列中的 reading/removing 消息的第二个进程。 创建的是 create_only_t。如果它已经存在,我希望它失败。然而,第一个队列的创建总是失败。它抛出的具体异常是File exists.

当切换到 open_or_create_t 队列时,它工作正常。我获取此信息是因为我没有正确清理它,所以我确保在尝试创建队列之前以及进程完成发送所有消息之后尝试删除队列。 如果删除成功,我会记录。我的假设之一是,如果 remove returns 为真,则意味着它已成功删除队列。 remove 的提升文档显示:“从系统中删除消息队列。Returns 出错时为 false。”,我不确定是否 true 只是意味着它成功 'attempt' 在删除它。进一步查看另一个 Boost Inprocess pdf 它解释说:

The remove operation might fail returning false if the shared memory does not exist, the file is open or the file is still memory mapped by other processes

无论哪种情况,如果队列始终 returns 为真,我觉得人们会希望将其删除,这就是我目前的情况。 仍然在尝试执行 'create_t' 消息队列时它将继续失败,但 'open_or_create_t' 仍然有效。

我很难理解这种行为,所以在尝试初始化 create_t 队列以查看第二个队列是否会 fail/return 之前,我还尝试连续两次删除消息队列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 from the C standard library.

只需限定您的通话:

bool first_removal = message_queue::remove(msg_queue_name);

措施

你能做什么:

  • 写卫生守则
    • 避免使用命名空间指令
    • 避免 ADL 陷阱
    • 使用警告(至少 -Wall -Wextra -pedantic)
    • 使用 linters。见下文
  • 检查你的假设(简单地进入调试器就会告诉你发生了什么)

Linters?

例如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;

这提示我可能有可疑之处。

修复

稍后修复其中的几个,代码运行

靠 Coliru 生活

#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

当然现在你的逻辑可以大大简化了:

Live On Coliru

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