为什么子进程无法写入共享内存?

时间:2014-07-28 10:33:30

标签: c

我有一个简单的程序写入共享内存并从共享内存中读取,但在阅读时我遇到了分段错误。

当我调试时,子进程没有将信息写入共享内存,之后,父进程正在尝试从没有数据的共享内存中读取并且在第一个printf中抛出分段错误,在父进程中printf("%d\n",ptr->nread);

为什么子进程无法将数据写入共享内存? (它在ptr->nread=20;行失败)

#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/shm.h>
#define  SIZE 5*1024
struct databuf{
    int nread;
    char *buf;
    int xyz;
};
    struct databuf* ptr;
main()
{
    int shmid,pid;
    shmid = shmget((key_t)1,SIZE,IPC_CREAT|0777);
    pid =  fork();
    if(pid==0)
    {
            ptr = (struct databuf *)shmat(shmid,(char*)0,0);
            ptr->nread=20;
            ptr->buf=ptr+sizeof(ptr->nread);
            strcpy(ptr->buf, "abc");
            ptr->xyz=20;
    }
    else
    {
        wait(0);
        ptr = (struct databuf *)shmat(shmid,(char*)0,0);
        printf("%d\n",ptr->nread);
        printf("%s\n",ptr->buf);
        printf("%d\n",ptr->xyz);
    }
    return 0;
}

3 个答案:

答案 0 :(得分:2)

如果ptr->nread失败,那么在进入ptr之前,你应该在这里输入错误检查代码。

 ptr = (struct databuf *)shmat(shmid,(char*)0,0);
 if (data == (struct databuf *)(-1)) {
                perror("shmat failed");
                exit(1);
 }
 ptr->nread=20;

参考:http://linux.die.net/man/2/shmat

ptr->buf=ptr+sizeof(ptr->nread);

可以写成:

 ptr->buf=(char*)ptr+sizeof(struct databuf)+ptr->nread;

 ptr->buf=(char*)ptr+ptr->nread;

现在可以在父进程中访问该字符串。

简要说明: 如果您正在使用共享内存,则必须确保要在其他进程中访问的所有数据都在共享内存段中。将数据保留在内存段中的指定偏移量(在您的情况下为ptr+ptr->nread)。并注意不要覆盖共享内存中的现有数据。 sizeof(ptr-> nread)将产生sizeof(int)。

答案 1 :(得分:1)

我认为,将代码中的所有其他问题留给一方:

shmid = shmget((key_t)1, SIZE, IPC_CREAT|0777) ;

可能是一个错误,除非你能(以某种方式)保证(key_t)1不在其他地方使用。对于亲子沟通,在这种情况下,更简单的方法是:

shmid = shmget((IPC_PRIVATE, SIZE, IPC_CREAT|0777) ;

一般来说,当一些显然莫名其妙的事情发生时,我发现确保检查错误返回是有帮助的。在这种情况下:shmget()返回-1shmat()返回-1 ...我怀疑两者都已发生。


@WhozCraig添加的工作解决方案:

以下示例正常工作可能执行您要完成的任务。在我们将ptr->buf置于共享内存基地址之后,请注意我们如何计算存储在ptr中的地址。我们必须为结构留出空间,所以我们计算地址以开始第一个字节过去结构背面。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/shm.h>

struct databuf
{
    int nread;
    char *buf;
    int xyz;
};

#define SIZE (5*1024)

int main()
{
    // acquire shared memory first (read/write access)
    int shmid = shmget(IPC_PRIVATE, SIZE, IPC_CREAT|0666);
    if (shmid == -1)
    {
        perror("Failed to acquire shared emory.");
        exit(EXIT_FAILURE);
    }

    // fork child process
    pid_t pid = fork();

    // both parent and child need this. may as well do both before
    //  special casing child vs. parent logic.
    struct databuf *ptr = shmat(shmid,(char*)0,0);
    if (ptr == (void*)(-1))
    {
        perror("Failed to map shared memory to our process");
        exit(EXIT_FAILURE);
    }

    // child process
    if (pid==0)
    {
        ptr->nread = 20;
        ptr->buf = ((char*)ptr) + sizeof(*ptr);
        strcpy(ptr->buf, "abc");
        ptr->xyz = 30;
    }

    // parent process
    else
    {
        wait(NULL);
        printf("ptr = %p, ptr->buf = %p\n", ptr, ptr->buf);
        printf("%d\n",ptr->nread);
        printf("%s\n",ptr->buf);
        printf("%d\n",ptr->xyz);
    }
    return 0;
}

样本输出(明显因系统而异)

ptr = 0x80000, ptr->buf = 0x8000c
20
abc
30

值得注意的是:

ptr->buf = ((char*)ptr) + sizeof(*ptr); 

可以使用类型指针数学编写如下:

ptr->buf = (char*)(ptr + 1);

施放石膏的位置很重要。第一个在我们做任何数学之前应用它,所以我们需要考虑八位字节数。第二个在指针数学之后将其应用于,因此只需在类型指针ptr中添加一个就会将我们移动到紧跟在ptr结构基础之后的内存中。

祝你好运。

答案 2 :(得分:0)

如果你有一个来自类型T的指针,那么将一个指针添加到指针将使它增加sizeof(T)。

所以你必须更换:

ptr->buf=ptr+sizeof(ptr->nread);

ptr->buf= ((char*)ptr )+sizeof(ptr->nread);

如果你不这样做,你的指针将增加sizeof(T)^ 2。