在此示例中,为什么没有关于Boost Interprocess message_queue的争用?

时间:2019-01-21 13:27:57

标签: c++ boost message-queue boost-interprocess

我正在尝试为Boost Interprocess message_queue设计一个好的命名方案。假设有一组进程都使用同一队列。这组过程可能同时存在多个“运行”。我假设每次运行都需要在进程组中使用的每个队列使用唯一的名称。以下原型代码将一堆消息发送到服务器进程,该服务器进程从队列中读取消息,然后打印它们:

#include <boost/archive/binary_iarchive.hpp>
#include <boost/archive/binary_oarchive.hpp>
#include <boost/interprocess/ipc/message_queue.hpp>
#include <boost/serialization/string.hpp>

#include <iostream>
#include <vector>

#include <unistd.h>

namespace ipc = boost::interprocess;

constexpr unsigned messages{1000000};
constexpr unsigned maxMessageSize{8192};

struct Message
{
  std::string prefix;

  template<typename Archive>
  void serialize(Archive& ar, const unsigned int)
  {
    // clang-format off
    ar & prefix;
    // clang-format on
  }
};

int loggerServerMain()
{
  try
  {
    // Open a message queue.
    ipc::message_queue mq(ipc::open_only, "message_queue");

    unsigned int priority;
    ipc::message_queue::size_type recvd_size;

    for (int i = 0; i < messages; ++i)
    {
      std::string data;
      data.resize(maxMessageSize);

      mq.receive(&data[0], maxMessageSize, recvd_size, priority);
      if (recvd_size > maxMessageSize)
        return 1;

      std::istringstream iss{data};
      boost::archive::binary_iarchive ia{iss};

      Message message;
      ia >> message;

      std::cout << message.prefix << '\n';
    }
  }
  catch (const ipc::interprocess_exception& ex)
  {
    std::cout << ex.what() << std::endl;
    return 1;
  }
  ipc::message_queue::remove("message_queue");
  return 0;
}

int main()
{
  try
  {
    ipc::message_queue::remove("message_queue");
    ipc::message_queue mq(ipc::create_only, "message_queue", 100, maxMessageSize);

    if (fork() == 0)
    {
      exit(loggerServerMain());
    }

    for (int i = 0; i < messages; ++i)
    {
      Message message{"lib" + std::to_string(i)};

      std::ostringstream oss;
      boost::archive::binary_oarchive oa{oss};
      oa << message;

      std::string data{oss.str()};
      mq.send(data.data(), data.size(), 0);
    }
  }
  catch (const ipc::interprocess_exception& ex)
  {
    std::cout << ex.what() << std::endl;
    return 1;
  }

  return 0;
}

因此,我们有一个过程可以派生一台服务器,然后继续将一堆消息发送到服务器,该服务器随后将打印消息。我们将硬编码名称“ message_queue”用作基础消息队列的名称。

我很惊讶地发现,当同时启动此过程的多个实例时,该示例仍然可以工作,例如:

./message_queue > 1.log & ; sleep 1 ; ./message_queue > 2.log

两个日志均以正确的顺序包含所有消息。 message_queue的第一个实例在第二个实例启动时仍在运行。这两个日志都是同时创建和写入的。

当同时从多个进程“组”中使用时,怎么可能没有消息队列争用?我假设消息队列的名称是在系统级别定义的一些全局名称,但是从我的示例看来,它是以某种方式在每个进程树中定义的?我浏览了Boost Interprocess的文档,但是找不到任何提及。

我正在使用Linux 4.20,GCC 8.1.0。示例代码编译如下:

g++ -std=c++17 -O3 -o message_queue message_queue.cpp -lpthread -lboost_serialization -lrt

0 个答案:

没有答案