我有一个简单的程序写入共享内存并从共享内存中读取,但在阅读时我遇到了分段错误。
当我调试时,子进程没有将信息写入共享内存,之后,父进程正在尝试从没有数据的共享内存中读取并且在第一个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;
}
答案 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()
返回-1
或shmat()
返回-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。