使用boost进程创建消息队列 - 内存访问冲突

问题描述 投票:1回答:1

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

  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个回答
3
投票

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

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,共享内存等的上下文中,使用任何类型的非平凡类都是非启动性的。

© www.soinside.com 2019 - 2024. All rights reserved.