使用 boost 进程间创建消息队列 - 内存访问冲突
Creating a message queue using boost interprocess - memory access violation
我正在创建一个由两个进程使用的消息队列。其中一个在里面放东西,另一个在读。
消息队列遵循我创建的结构。
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。
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;
}
}
放置动作的第二个程序工作正常。但是在它之后 运行 主程序发现计数增加了并且正在尝试读取并向我抛出内存访问冲突。
我不知道为什么会收到此违规错误。共享 class 对象或结构有什么特别之处吗?
让我们看一下您试图在进程之间传递的对象:
class Action {
// ...
std::string name_;
}
嗯,看这里。我们有什么在这里?我们这里有一个 std::string
.
你知道吗 sizeof(x)
,其中 x
是一个 std::string
将始终给你相同的答案,无论字符串是空的,还是包含 [=] 的全部内容47=]?那是因为您的 std::string
做了很多您实际上不需要考虑的工作。它负责为字符串分配所需的内存,并在不再使用时释放内存。当 std::string
被复制或移动时,class 负责正确处理这些细节。它自己进行内存分配和释放。你可以把你的 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
。
这不会有好结果。
你唯一现实的选择是用一个普通的 char
数组替换 std::string
,然后进行额外的工作以确保它被正确初始化,不会溢出等。 ..
一般来说,在 IPC、共享内存等...的上下文中,使用任何类型的非平凡 class 都是行不通的。
我正在创建一个由两个进程使用的消息队列。其中一个在里面放东西,另一个在读。 消息队列遵循我创建的结构。
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。
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;
}
}
放置动作的第二个程序工作正常。但是在它之后 运行 主程序发现计数增加了并且正在尝试读取并向我抛出内存访问冲突。
我不知道为什么会收到此违规错误。共享 class 对象或结构有什么特别之处吗?
让我们看一下您试图在进程之间传递的对象:
class Action {
// ...
std::string name_;
}
嗯,看这里。我们有什么在这里?我们这里有一个 std::string
.
你知道吗 sizeof(x)
,其中 x
是一个 std::string
将始终给你相同的答案,无论字符串是空的,还是包含 [=] 的全部内容47=]?那是因为您的 std::string
做了很多您实际上不需要考虑的工作。它负责为字符串分配所需的内存,并在不再使用时释放内存。当 std::string
被复制或移动时,class 负责正确处理这些细节。它自己进行内存分配和释放。你可以把你的 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
。
这不会有好结果。
你唯一现实的选择是用一个普通的 char
数组替换 std::string
,然后进行额外的工作以确保它被正确初始化,不会溢出等。 ..
一般来说,在 IPC、共享内存等...的上下文中,使用任何类型的非平凡 class 都是行不通的。