我正在学习fork()如何在C中工作。 这个想法是产生3个子进程,每个进程都向父进程发送一些信息。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main()
{
int fd[2];
int pid[3] = {0,0,0};
int status = 0;
for (int i = 0; i < 3; i++)
{
pipe(fd);
pid[i] = fork();
if (pid[i] < 0)
{
return -1;
}
if (pid[i] == 0)
{
close(fd[0]);
char *arr = malloc(sizeof(char));
sprintf(arr, "%i", i);
write(fd[1], arr, 1);
exit(0);
}
}
for(int j=0; j < 3; j++)
{
close(fd[1]);
if (pid[j] > 0)
{
sleep(0);
pid[j] = wait(&status);
char *out = malloc(20 *sizeof(char));
read(fd[0], out, 6);
printf("%s\n", out);
free(out);
printf("I am the parent\n");
}
}
}
预定的输出是:
1
I am the parent
2
I am the parent
3
I am the parent
实际输出是: 2 我是父母 2 我是父母 2 我是父母
为什么会这样?
答案 0 :(得分:1)
您正在致电
pipe(fd);
在第一个for
循环中多次。考虑在循环之前移动它,因为它每次调用它时都会返回一对新的文件描述符进行读/写。
此外,close(fd[1])
只应从父进程调用一次。
答案 1 :(得分:0)
几点:
您在第一个pipe(fd)
循环中呼叫for
三次,而当您创建三个管道时,您只需保存一个引用其中之一。因此,在您的第二个for
循环中,您将从每次创建的第三个管道中读取数据。您应该有一个数组来存储对所有三个管道的引用。
您应该检查可能失败的系统调用的所有的返回。由于上面的第1点,close(fd[1])
如果你做了这个,就会失败两次,而且它会提醒你事情已经发生了。检查系统调用的返回不仅是为了防止出现不太可能发生的错误,而且还可以帮助您进行调试,因为它们失败的最可能原因是你做错了,就像这里的情况一样。
完全没有必要使用malloc()
,这里 - 常规的char
数组很好。此外,当您需要至少两个(即单个数字和终止空字符)时,malloc(sizeof(char));
为一个字符分配空间。此外,您应始终检查malloc()
的退货,因为它可能会失败。此外,根据定义,sizeof(char)
始终为1
,因此它总是多余的。
要获得所需的输出,您应该将1
添加到i
,否则i
将是0
,然后是1
,然后2
,但您的示例输出显示您想要1
,然后2
和3
。
waitpid()
优于wait()
,因为您希望等待特定流程。同样,使用此功能时,sleep()
来电也是多余的。
虽然在您退出之前没有必要close()
您的管道,但这样做有时会有所帮助,因为如果您和& #39;做错了什么。
您的if (pid[j] > 0)
检查是不必要的,因为如果fork()
失败或0
失败,您已经终止,因此您已经知道它将会是当你到达这里时,大于0
。
如果您不打算使用它,则不需要status
变量来检索流程的退出状态 - 您只需将NULL
传递给wait()
即可waitpid()
或j
。
小点,但您不需要为第二个for
循环使用不同的变量名称(即i
),因为for
的范围在您的第一个i
循环中仅限于该循环。如果您要使用return EXIT_FAILURE
作为循环计数器的通用名称,您可以随时随地使用它。
return -1
优于255
,无论如何,当您检索退出状态时,该值将转换为fork()
。
实际上它不太可能是一个问题,但是pid_t
会返回int
类型,而不是类型pid
,所以它更好使#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(void)
{
int fd[3][2];
pid_t pid[3];
for ( int i = 0; i < 3; ++i ) {
if ( pipe(fd[i]) == -1 ) {
perror("pipe() failed");
return EXIT_FAILURE;
}
if ( (pid[i] = fork()) == -1 ) {
perror("fork() failed");
return EXIT_FAILURE;
}
else if ( pid[i] == 0 ) {
if ( close(fd[i][0]) == -1 ) {
perror("close() failed");
return EXIT_FAILURE;
}
char arr[100];
sprintf(arr, "%d", i + 1);
if ( write(fd[i][1], arr, 1) == -1 ) {
perror("write() failed");
return EXIT_FAILURE;
}
if ( close(fd[i][1]) == -1 ) {
perror("close() failed");
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
else {
if ( close(fd[i][1]) == -1 ) {
perror("close() failed");
return EXIT_FAILURE;
}
}
}
for ( int i = 0; i < 3; ++i ) {
if ( waitpid(pid[i], NULL, 0) == -1 ) {
perror("waitpid() failed");
return EXIT_FAILURE;
}
char out[100] = {0};
if ( read(fd[i][0], out, 99) == -1 ) {
perror("read() failed");
return EXIT_FAILURE;
}
printf("%s\nI am the parent\n", out);
if ( close(fd[i][0]) == -1 ) {
perror("close() failed");
return EXIT_FAILURE;
}
}
return EXIT_SUCCESS;
}
成为该类型的数组。
这里有一些修改过的代码:
paul@horus:~/src/sandbox$ ./pipe
1
I am the parent
2
I am the parent
3
I am the parent
paul@horus:~/src/sandbox$
输出:
{{1}}