如何在C语言中使用共享内存,在两个不相关的进程之间共享一个带指针的结构体?

4

我有一个结构看起来像:

typedef struct shared_data_t
{
    char *key;
    char *message;
}shared_data;

我需要与另一个无关的进程共享这个结构。我使用了POSIX共享内存并使用shm_open()/mmap()来实现。但是我的目标进程没有获得共享数据,并且由于SIGSEGV而终止,这是显而易见的。如果有人能帮我解决这个问题,特别是在使用共享内存(shm_open和mmap)共享指针时会发生什么,那就太好了。
对于这样的一个结构:
typedef struct shared_data_t
{
    char key[8];
    char message[32];
}shared_data;

它运行得很好!


这很好用!你只是忘记了这些指针指向共享内存之外,所以另一个进程无法获取数据。但是你也可以在共享内存中分配“键”和“消息”。或者真正制作一个没有指针的特定结构! - Eddy_Em
2
这些指针引用的内存最好也是共享的,否则这就有点毫无意义了。 - WhozCraig
1
使用共享内存开头的偏移量而不是指针。 - n. m.
@Eddy_Em 谢谢您的回复。我尝试使用memcpy将结构内容复制到共享内存中,但目标进程仍然无法获取它。我是否漏掉了非常明显的东西? - Saurav Haloi
2个回答

5
在Linux的shmat手册页中有一条注释:
使用shmat()并将shmaddr设置为NULL是一种首选、可移植的方法来附加共享内存段。请注意,以这种方式附加的共享内存段可能会在不同的进程中附加到不同的地址上。因此,必须将共享内存中维护的任何指针相对于段的起始地址进行处理,而不是绝对地址。

谢谢您的回复。我正在使用shm_open / mmap方式来进行IPC共享内存。当然,我将mmap的第一个参数设置为NULL,以便让内核决定在哪里放置内存段。 - Saurav Haloi

3
该结构包含两个指针,用于表示key和message。它们的值为0x1000和0x1040等。您的第一个进程将映射共享内存,比如在地址0x7000处。它将结构体复制到共享内存中。第二个进程将映射同一共享内存,比如在地址0x9000处。它读取结构体。然后使用指针来查找key和message,导致它在地址0x1000和0x1040处寻找,但是它们不在第二个进程的内存中的这些地址。因此第二个进程失败了。
要解决此问题,您必须安排key和message位于共享内存中,并且您必须要么安排它们在两个进程中具有相同的地址(通过告诉mmap确切地想要映射内存的位置,而不是让系统选择地址),要么在共享内存中包含有关如何定位key和message的信息。这通常是通过使用偏移量而不是指针来完成的。也就是说,不是在结构体中有指向char的指针,而是具有偏移量,用于给出从基本位置到键和消息的字节数。共享内存段的开头是使用的典型基础。
如果您只有一个key和一个message需要共享,则通常的方法是仅使用一个数据结构用于共享内存,就像您展示的第二个shared_data定义一样:key和message是结构体的一部分,因此它们的偏移量已知,仅作为结构体开头的偏移量。如果您正在共享更复杂的数据,例如树或链表,则可能需要使用显式偏移量。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接