【问题标题】:Creating a message queue using boost interprocess - memory access violation使用 boost 进程间创建消息队列 - 内存访问冲突
【发布时间】:2018-06-21 10:39:13
【问题描述】:

我正在创建一个由两个进程使用的消息队列。其中一个在里面放东西,另一个在读。 消息队列遵循我创建的结构。

  struct MSGQueue {
    Action actions_[256];
    int count;
    MSGQueue() { count = 0; }

    interprocess_mutex mutex;

    Action Pop() {
      --count;
      return actions_[count];
    }

    void Put(Action act) {
      actions_[count] = act;
      ++count;
    }
  };

Action 是我创建的自定义类。

class Action {
 public:
  // Getter functions for the member 

 private:
    std::string name_;
    ActionFn action_fn_; // this is an enum
    void* additional_data_;
 }

我正在主程序中创建这样的共享内存

  shm_messages = shared_memory_object(create_only,"MySharedMemory", read_write);
  shm_messages.truncate(sizeof(MSGQueue));
  region = mapped_region(shm_messages_, read_write);

在我的另一个程序中,我打开它并将一个动作放入队列的动作数组中。

  boost::interprocess::shared_memory_object shm_messages_;
  boost::interprocess::mapped_region region_;

  shm_messages_ = shared_memory_object(open_only, "MySharedMemory", read_write);
  shm_messages_.truncate(sizeof(MSGQueue));
  region_ = mapped_region(shm_messages_, read_write);

  //Get the address of the mapped region
  void * addr       = region_.get_address();
  //Construct the shared structure in memory
  MSGQueue * data = static_cast<MSGQueue*>(addr);

  Action open_roof("OpenRoof", ActionFn::AFN_ON, NULL);

  { // Code block for scoped_lock. Mutex will automatically unlock after block.
    // even if an exception occurs
    scoped_lock<interprocess_mutex> lock(data->mutex);

    // Put the action in the shared memory object
    data->Put(open_roof);
  }

主程序正在检查我们是否收到了一些新消息,如果有,它将读取它并将其放入列表中。

  std::vector<ghpi::Action> actions;

  //Get the address of the mapped region
  void * addr       = region_.get_address();
  //Construct the shared structure in memory
  MSGQueue * data = static_cast<ghpi::Operator::MSGQueue*>(addr);
  if (!data) {
    std::cout << " Error while reading shared memory" << std::endl;
    return actions;
  }

  {
    scoped_lock<interprocess_mutex> lock(data->mutex);

    while (data->count > 0) {
      actions.push_back(data->Pop()); // memory access violation here
      std::cout << " Read action from shm" << std::endl;
    }
  }

执行该操作的第二个程序运行良好。但在它运行后,主程序看到计数增加并试图读取并向我抛出内存访问冲突。

我不知道为什么会收到此违规错误。共享类对象或结构有什么特别之处吗?

【问题讨论】:

    标签: c++ boost interprocess boost-interprocess


    【解决方案1】:

    让我们看看你试图在进程之间传递的对象:

    class Action {
    
    // ...
        std::string name_;
    }
    

    好吧,看这里。我们有什么在这里?我们这里有一个std::string

    您是否知道sizeof(x),其中xstd::string,无论字符串为空还是其全部内容都是“战争与和平”,都会给您相同的答案?那是因为你的 std::string 做了很多你不需要考虑的工作。它负责为字符串分配所需内存,并在不再使用时取消分配。当std::string 被复制或移动时,该类负责正确处理这些细节。它自己进行内存分配和释放。您可以认为您的 std::string 包含以下内容:

    namespace std {
        class string {
             char *data;
             size_t length;
    
             // More stuff
        };
    }
    

    通常在您的典型花园品种std::string 中还有更多内容,但这让您了解正在发生的事情的基本概念。

    现在试着想想当你将std::string 放入共享内存时会发生什么。你认为char 指针仍然指向哪里?当然,它仍然指向某个地方,某个地方,在您的进程内存中,您的std::string 为它所代表的任何字符串分配了内存。你不知道在哪里,因为所有这些信息都隐藏在字符串中。

    所以,您将这个std::string 放在您的共享内存区域中。您确实放置了 std::string 本身,但当然不是它包含的实际字符串。您不可能这样做,因为您无法访问std::string 的内部指针和数据。所以,你已经做到了,你现在正试图从其他进程访问这个std::string

    这不会有好的结局。

    您唯一现实的选择是将std::string 替换为普通的char 数组,然后进行额外的工作以确保它已正确初始化、不会溢出等...

    通常,在 IPC、共享内存等的上下文中,使用任何类型的非平凡类都是不可行的。

    【讨论】:

    • 如果 OP 愿意用托管内存段替换“原始”共享内存对象,可以简单地使用进程间分配器并继续使用basic_string,在保持 C++ 抽象质量的进程中。我在这个网站上有a pretty big number of examples demonstrating this(特别是basic_string,但也有几个也有进程间队列)。
    • 好的,我用一个 char 数组替换了它,现在它可以工作了。非常感谢你:)
    猜你喜欢
    • 2019-05-01
    • 1970-01-01
    • 1970-01-01
    • 2017-02-14
    • 1970-01-01
    • 1970-01-01
    • 2020-11-17
    • 2021-05-21
    • 1970-01-01
    相关资源
    最近更新 更多