C - 管道和分叉 - 奇怪的记忆垃圾

时间:2016-12-09 22:40:29

标签: c pipe fork

我正在尝试完成以下任务:

有两个过程,父母和孩子。父母在管道上向孩子发送“位置”(代码中的纽约),然后通过SIGUSR1向父流程发信号通知该位置已到达。然后,父进程将注册访问者列表发送到子进程(visitordata* V),该进程由结构visitordata的条目组成:

typedef struct visitordata {
    char name[80];
    char email[80];
    int id;
    char reg_time[9];
} visitordata;

到目前为止,我的代码中的一切正常。现在,子进程应该向父进程发送一个随机数(视为'质量'),并且实际访问者(每个注册访问者有90%的机会实际参加该事件),这就是我的代码失败。我正在尝试将数据发送回父进程,就像我将其发送给子进程一样:

int pipefd[2];
if (pipe(pipefd) < 0) { perror("Pipe error!\r\n"); exit(1); }   

//int numactualvisitors is the actual number of visitors that went to the event
quality = rand() % 10 + 1;
visitordata* actualvisitors = (visitordata*)malloc(numactualvisitors * sizeof(visitordata));
write(pipefd[1], &numactualvisitors, sizeof(numactualvisitors));
printf("ee\n");             
write(pipefd[1], actualvisitors, numactualvisitors * sizeof(visitordata));
printf("ff\n");
write(pipefd[1], &quality, sizeof(quality));
printf("gg\n");

但是,不是写入管道,似乎写入实际上发生在控制台上,我得到的输出如下:

dd
ee
userfirstname lastnameemail@email-15:22:38firstname2 lastname2email@email▒15:22:49ff
gg

同时,父进程应该读取它(我需要sleep(1),因为否则读取发生的时间早于其他进程中的写入):

printf("first\n");
sleep(1);
int dv;
int qual;
printf("debug1");

read(pipefd[0], &dv, sizeof(int));
printf("%d\n", dv);
printf("debug2");

visitordata* A;
A = (visitordata*)malloc(dv * sizeof(visitordata));         
printf("debug3");
read(pipefd[0], A, dv * sizeof(visitordata));
printf("dv: %d\n", dv);
read(pipefd[0], &qual, sizeof(int));

但是,由此,只有first字符串被写入控制台。该程序没有完成,它挂起了。我究竟做错了什么?我无法理解为什么父母不会超过first点,以及为什么孩子将结构数组写入控制台而不是发送它。我目前正在测试只有2行输入,所以基本上它将两个注册的与会者都放到了控制台上。我不太明白。

您可以找到更多代码here,以便更好地了解这些代码。我将保留printf - s,以便我们可以更好地引用代码的各个部分。

感谢您的帮助!

1 个答案:

答案 0 :(得分:0)

原始错误在父代码中:

visitordata* V;
…
  write(pipefd[1], &V, ds * sizeof(visitordata));

通过使用&V,它尝试写入的不是指针数据,而是指针V地址的相应字节数。在该地址处,可能没有足够的可访问内存,因此write可能会失败,从而导致子级永远等待读取数据。正确:

  write(pipefd[1], V, ds * sizeof (visitordata));

此外,由于您sleep(1)父母和孩子都一样,因此不能保证孩子在父母希望读取实际访问者的数量之前先读取访问者数据,所以,因为您使用从父级到子级进行反向通信的管道相同,父级可能会读取与其写入的数据完全相同的数据。最好将一个管道用于父对子方向,将另一个管道用于子对父方向;那么您就不需要sleep()了,无论如何这是一种不可靠的同步方法。