从共享内存存储和访问结构数组

Posted

技术标签:

【中文标题】从共享内存存储和访问结构数组【英文标题】:Storing and accessing an array of struct from shared memory 【发布时间】:2018-11-13 08:38:36 【问题描述】:

我正在酒店预订系统上编写一个程序,并声明了一个结构 Room,如下所示:

struct Room 
bool isavailable;
bool ispaid;
string customer;
string date;
;

我使用从输入文件中读取的变量来创建一个包含 n 个结构的数组,它是酒店中的所有房间。

struct Room* rooms = new Room[numOfRooms];

然后我创建共享内存空间并附加它,但是当我尝试访问它之后,它似乎不起作用。

//creates shared memory space
if((shmid = shmget(shmkey, 1000, IPC_CREAT | 0666)) < 0) 
    perror("Failed to allocate shared mem");
    exit(1);


//attaches shared memory to process
Room* shared_memory;
shared_memory = (Room* ) shmat(shmid, NULL, 0);
if(!shared_memory) 
    perror("Error attaching");
    exit(0);


struct Room *PTR = rooms; //temp pointer to rooms array
cout << "test: " << rooms[1].customer << endl; //print before storing in shared memory
rooms = (struct Room*) shared_memory+sizeof(int); //places rooms array in shared memory
delete [] PTR; //deletes the memory location where rooms was stored before being in shared memory
cout << "test: " << rooms[1].customer << endl; //print after storing in shared mem

如您所见,在将房间移动到共享内存之前,我有一个 cout 语句,它会打印正确的内容,但之后的 cout 是空的。任何帮助将不胜感激,谢谢。

【问题讨论】:

std::string 对象在堆中动态分配它们的内存。字符串数据本身不会在共享内存中,只有指向内存的指针。使用任何类型的动态结构和数据对于共享内存(以及一般的 IPC)来说都是非常重要的。 您没有将rooms 数组移动到共享内存中。此外,在 C++ 中,无法在内存中移动对象(您可以复制它们的字节表示,但仅限于 trivially-copyable 类型,这不是您的情况,因为string 成员变量) .您可以移动对象的内容,但这需要使用移动构造函数和放置新语法来构造它们(在未初始化的内存中)。即使这样,在长字符串的情况下,它们的字符仍将保留在(非共享)堆中。您将仅共享 string 对象本身,而不是存储的字符串。 @DanielLangr 那么如果我将字符串成员变量重写为字符呢? @Bzm10823 如果您使用某个预定义大小的 char 数组,那么就可以了(例如 char customer[100];。如果您使用动态分配的 char 数组,那么您将遇到与std::string. 【参考方案1】:

rooms = (struct Room*) shared_memory+sizeof(int); //places rooms array in shared memory

这行不符合您的评论所说的。首先,shared_memory 已经被声明为Room* shared_memory,因此不需要强制转换。将sizeof(int)(假设为4)添加到指针将使指针指向第4个这样的元素,即如果shared_memory指向Room arr[N]数组的第一个元素,则表达式shared_memory + i是等于&amp;arr[i]。在这种情况下,shared_memory+sizeof(int) 是指向第 4 个(或sizeof(int)'th)元素的指针——或者更确切地说,该元素在shared_memory 中的位置,因为您刚刚创建了共享内存并且没有放置任何实际的Rooms 还在里面。

最后,rooms = ... 只是为 指针 赋值。所以现在rooms 变量(它是一个指针,基本上只是一个数字)指向shared_memory 数组中第四个Room 对象所在的位置。它不会复制使用new Room[numOfRooms] 或类似的东西创建的数组。

另请参阅:How do pointer to pointers work in C?

您要做的是将对象复制到共享内存中。一般来说,您可以像这样使用std::copy

std::copy(&rooms[0], &rooms[numOfRooms], shared_memory);

但问题在于std::string 包含一个指向char 数组的指针,您可以假设该数组是用new char[length_of_string] 分配的。 (这是事实的简化版本,但足够了。)上面的std::copy不会将此内部数组移动到共享内存中,因此如果将共享内存映射到另一个进程并访问字符串数据。 (您可能会读取内存垃圾,或者在尝试访问未映射的内存时可能会出现段错误。)要解决此问题,您需要使用可以从共享内存中分配的分配器类型,或者将字符串与struct ShortString char data[/*max length*/ 20]; 之类的内联存储。如果您需要帮助,可以搜索或发布其他问题。

【讨论】:

所以我从结构中删除了字符串成员并替换了房间 = (struct Room*) shared_memory+sizeof(int);与您提供的似乎有效的副本一致。我猜它现在正在完全访问共享内存中的结构?我将把它与信号量一起使用,这样多个子进程就可以在没有竞争条件的情况下编辑结构

以上是关于从共享内存存储和访问结构数组的主要内容,如果未能解决你的问题,请参考以下文章

02 堆内存和栈内存数据存储过程| 数组 | 栈结构面试题击鼓传花讲解

数据结构概览

数据结构概括

JMM内存模型

存储管理

数据结构