我想要实现的是,创建 2 个子进程说“左”和“右”,左子进程执行一个名为 ./left 的进程,该进程从 stdin 获取 2 个输入并将其求和,然后通过 stdout 将其转发到其父进程。然后右子进程再次执行一个进程,再次对 2 个 stdin 输入求和并将其转发给其父进程。在下面的代码中,左侧结果成功处理并通过 stderr 打印,但右侧结果是垃圾值,我不明白为什么。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
int main() {
//###### 0 is read end, 1 is write end
int p2c_l[2]; // Parent to child left pipe, p2c[0] is read end, p2c[1] is write end from parent perspective
int c2p_l[2]; // Child to parent left pipe
// Create pipes
pipe(p2c_l);
pipe(c2p_l);
int pid = fork();
if (pid == 0) { //Left child
fprintf(stderr, "Left child process\n");
// close right child pipes
close(c2p_l[0]);
close(p2c_l[1]);
dup2(p2c_l[0], 0);
dup2(c2p_l[1], 1);
char* args[] = {"./left", NULL};
execvp(args[0], args);
fprintf(stderr, "Left child process failed\n");
exit(EXIT_FAILURE);
} else { // Parent process
close(c2p_l[1]);
close(p2c_l[0]);
// dup2(p2c_l[1], 1);
// dup2(c2p_l[0], 0);
fprintf(stderr, "Parent process after first fork\n");
int n1, n2;
n1 = 5;
n2 = 10;
write(p2c_l[1], &n1, sizeof(n1));
write(p2c_l[1], &n2, sizeof(n2));
int resultFromLeftChild;
read(c2p_l[0], &resultFromLeftChild, sizeof(resultFromLeftChild));
fprintf(stderr, "Left child result: %d\n", resultFromLeftChild);
int p2c_r[2]; // Parent to child right pipe
int c2p_r[2]; // Child to parent right pipe
int pid2 = fork();
if (pid2 == 0) { //Right child
fprintf(stderr, "Right child process\n");
// close left child pipes
close(p2c_r[0]);
close(c2p_r[1]);
//make pc2_r[0] and c2p_r[1] as stdin and stdout
dup2(p2c_r[0], 0);
dup2(c2p_r[1], 1);
char* args[] = {"./right", NULL};
execvp(args[0], args);
fprintf(stderr, "Right child process failed\n");
exit(EXIT_FAILURE);
} else { // Parent process
close(p2c_r[1]);
close(c2p_r[0]);
// dup2(p2c_r[1], 1);
// dup2(c2p_r[0], 0);
fprintf(stderr, "Parent process after second fork\n");
int n1, n2;
n1 = resultFromLeftChild;
n2 = 10;
// printf("%d\n", n1);
// printf("%d\n", n2);
write(p2c_r[1], &n1, sizeof(n1));
write(p2c_r[1], &n2, sizeof(n2));
int resultFromRightChild;
read(c2p_r[0], &resultFromRightChild, sizeof(resultFromRightChild));
fprintf(stderr, "Right child result: %d\n", resultFromRightChild);
int result = resultFromLeftChild + resultFromRightChild;
fprintf(stderr, "Result: %d\n", result);
}
}
return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
int num1, num2;
if (argc != 1) {
printf("Usage: %s \n", argv[0]);
return 1; // Error code for incorrect usage
}
scanf("%d", &num1);
scanf("%d", &num2);
// Calculate the addition
int result = num1 + num2;
//printf("Inputs: %d %d \n", num1, num2);
// Print the result
printf("%d\n", result);
return 0; // Successful execution
}
我期望得到
Right child result: 25
作为输出,但我得到
Right child result: {garbage value}
作为输出。
问题的一部分是您没有关闭足够的管道描述符。
dup2()
连接到标准输入或标准输出,请尽快关闭 pipe()
中的两个原始文件描述符。特别是,这意味着在使用任何 exec*()
系列函数之前。该规则也适用于 dup()
或 fcntl()
与 F_DUPFD
。
当前代码修订版(修订版 4)中的另一个问题是子级希望使用
scanf()
读取 ASCII 数字,但父级发送二进制数。
最大的问题是您没有为子进程创建管道。 第二个问题是您关闭了父进程中右子管道的错误端。
解决这些问题会产生如下代码:
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <unistd.h>
int main(void)
{
// ###### 0 is read end, 1 is write end
int p2c_l[2]; // Parent to child left pipe, p2c[0] is read end, p2c[1] is write end from parent perspective
int c2p_l[2]; // Child to parent left pipe
// Create pipes
if (pipe(p2c_l) < 0 || pipe(c2p_l) < 0)
{
fprintf(stderr, "Failed to create pipes for left child: %d %s\n", errno, strerror(errno));
exit(EXIT_FAILURE);
}
int resultFromLeftChild = -1;
int pid1 = fork();
if (pid1 < 0)
{
fprintf(stderr, "Fork 1 failed: %d %s\n", errno, strerror(errno));
exit(EXIT_FAILURE);
}
if (pid1 == 0) // Left child
{
fprintf(stderr, "Left child process\n");
dup2(p2c_l[0], 0); // STDIN_FILENO?
dup2(c2p_l[1], 1); // STDOUT_FILENO?
close(c2p_l[0]);
close(c2p_l[1]);
close(p2c_l[0]);
close(p2c_l[1]);
char *args[] = {"./left", NULL};
execvp(args[0], args);
fprintf(stderr, "Left child process failed: %d %s\n", errno, strerror(errno));
exit(EXIT_FAILURE);
}
else // Parent process
{
close(c2p_l[1]);
close(p2c_l[0]);
fprintf(stderr, "Parent process after first fork\n");
int n1, n2;
n1 = 5;
n2 = 10;
char buffer[32];
snprintf(buffer, sizeof(buffer), "%d\n", n1);
write(p2c_l[1], buffer, strlen(buffer));
snprintf(buffer, sizeof(buffer), "%d\n", n2);
write(p2c_l[1], buffer, strlen(buffer));
int nbytes = read(c2p_l[0], buffer, sizeof(buffer));
if (nbytes <= 0)
fprintf(stderr, "Failed to read from child 1\n");
else
{
fprintf(stderr, "Left child result: %s\n", buffer);
resultFromLeftChild = atoi(buffer);
}
close(p2c_l[1]);
close(c2p_l[0]);
int corpse;
int status;
while ((corpse = wait(&status)) > 0)
printf("PID %d exited with status 0x%.4X\n", corpse, status);
}
/* Now repeat the code for the right child - this is where we use functions! */
int p2c_r[2]; // Parent to child right pipe
int c2p_r[2]; // Child to parent right pipe
// Create pipes
if (pipe(p2c_r) < 0 || pipe(c2p_r) < 0)
{
fprintf(stderr, "Failed to create pipes for right child: %d %s\n", errno, strerror(errno));
exit(EXIT_FAILURE);
}
int pid2 = fork();
if (pid2 < 0)
{
fprintf(stderr, "Fork 1 failed: %d %s\n", errno, strerror(errno));
exit(EXIT_FAILURE);
}
if (pid2 == 0) // Right child
{
fprintf(stderr, "Right child process\n");
dup2(p2c_r[0], 0);
dup2(c2p_r[1], 1);
close(p2c_r[0]);
close(p2c_r[1]);
close(c2p_r[0]);
close(c2p_r[1]);
char *args[] = {"./right", NULL};
execvp(args[0], args);
fprintf(stderr, "Right child process failed: %d %s\n", errno, strerror(errno));
exit(EXIT_FAILURE);
}
else // Parent process
{
close(p2c_r[0]);
close(c2p_r[1]);
fprintf(stderr, "Parent process after second fork\n");
int n1, n2;
n1 = resultFromLeftChild;
n2 = 10;
char buffer[32];
snprintf(buffer, sizeof(buffer), "%d\n", n1);
write(p2c_r[1], buffer, strlen(buffer));
snprintf(buffer, sizeof(buffer), "%d\n", n2);
write(p2c_r[1], buffer, strlen(buffer));
int nbytes = read(c2p_r[0], buffer, sizeof(buffer));
if (nbytes <= 0)
fprintf(stderr, "Failed to read from child 2\n");
else
fprintf(stderr, "Right child result: %s\n", buffer);
close(p2c_r[1]);
close(c2p_r[0]);
int corpse;
int status;
while ((corpse = wait(&status)) > 0)
printf("PID %d exited with status 0x%.4X\n", corpse, status);
}
return 0;
}
输出示例:
Parent process after first fork
Left child process
Left child result: 15
PID 57771 exited with status 0x0000
Parent process after second fork
Right child process
Right child result: 25
PID 57772 exited with status 0x0000