具有不同输出的管道的分叉进程
forked processes with pipes having different output
我有一些代码练习分叉进程(在命令行中模拟 (|))。但是,每次的输出都不一样。例如,对于 ./pipe ls cat wc
的输入,它应该与 ls | cat | wc
相同。但是,有时我的代码会输出
Child with PID 12126 exited with status 0x0.
Child with PID 12127 exited with status 0x0.
7 7 52
Child with PID 12128 exited with status 0x0.
但有时也会输出:
Makefile
pipe
#pipe.c#
pipe.c
pipe.o
README.md
test
Child with PID 12138 exited with status 0x0.
Child with PID 12139 exited with status 0x0.
0 0 0
Child with PID 12140 exited with status 0x0.
第一个输出是正确的(与ls | cat | wc
相比)。我发现通过第二个输出,程序 ls
和 cat
的管道输出没有被 wc
处理。我想知道我的程序出了什么问题,因为似乎我正确地设置了管道——第一个程序将从 stdin 获取输入并输出到管道的写入端,最后一个程序将从管道的读取端获取输入管道并输出到标准输出。感谢任何输入。
代码(./pipe
):
#include <stdio.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
int fd[2];
if (pipe(fd) == -1) {
int err = errno;
perror("pipe");
return err;
}
pid_t pid[argc-1];
int n = argc;
if(argc <= 1){
return EINVAL;
}
for (int i = 1; i < argc; i++){
if ((pid[i] = fork()) == -1){
int err = errno;
perror("fork");
return err;
}else if(pid[i] == 0){
//open(fd[1]);
if(i == 1){
dup2(fd[1],STDOUT_FILENO);
if (execlp(argv[i], argv[i], NULL) == -1) {
printf("failed to search for the provided executed program. \n");
return errno;
}
}else if(i == argc-1){
dup2(fd[0],STDIN_FILENO);
if (execlp(argv[i], argv[i], NULL) == -1) {
printf("failed to search for the provided executed program. \n");
return errno;
}
}else{
dup2(fd[0],STDIN_FILENO);
dup2(fd[1],STDOUT_FILENO);
if (execlp(argv[i], argv[i], NULL) == -1) {
printf("failed to search for the provided executed program. \n");
return errno;
}
}
}
close(fd[1]);
}
int wstatus;
pid_t pids;
while (n > 1) {
pids = wait(&wstatus);
printf("Child with PID %ld exited with status 0x%x.\n", (long)pids, wstatus);
--n;
}
}
您正在越界访问可变长度数组 pid
,因此您的程序具有 未定义的行为。
你可以通过将数组扩大一个元素来解决它:
pid_t pid[argc]; /* not argc - 1 */
另一个问题是你需要在每对命令之间建立一个新的管道。总的来说,一个管道少于命令的数量。也就是说,一个命令的管道为零。
stdin - ls - pipe - cat - pipe - wc - stdout // 3 commands, 2 pipes
这是一个想法,我在(几乎)循环的每次迭代中创建一个管道,并保存管道的输入端以供下一次迭代使用。我根本没有费心保存进程 id:s,也没有为 dup2
添加错误检查。但是,您应该检查它是否真的成功了。
#include <errno.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
int exec(const char* prog) {
if(execlp(prog, prog, NULL) == -1) {
perror("execlp");
}
return 1;
}
int main(int argc, char* argv[]) {
pid_t pid;
int in; // for saving the input side of the pipe between iterations
for(int i = 1; i < argc; ++i) {
int fd[2];
// must have at least 2 commands to create a pipe
// and we need one pipe less than the number of commands
if(argc > 1 && i < argc - 1) pipe(fd);
if((pid = fork()) == -1) {
perror("fork");
return 1;
} else if(pid == 0) {
if(i == 1) { // first command
if(argc > 1) { // must have more than one command to dup
dup2(fd[1], STDOUT_FILENO);
close(fd[1]);
close(fd[0]);
}
} else if(i == argc - 1) { // last command
dup2(in, STDIN_FILENO);
close(in);
} else { // middle commands
dup2(in, STDIN_FILENO);
close(in);
dup2(fd[1], STDOUT_FILENO);
close(fd[1]);
close(fd[0]);
}
return exec(argv[i]);
}
// parent
if(i > 1) close(in); // close old in
in = fd[0]; // save the stdin side of the pipe for next loop iteration
close(fd[1]); // no use for the stdout end
}
int wstatus;
while((pid = wait(&wstatus)) != -1) {
printf("Child with PID %ld exited with status 0x%x.\n", (long)pid,
wstatus);
}
}
您需要更多的管道,因为您当前的代码中只有一个。如果 ls
和 cat
都写入该管道,并且 cat
和 wc
都从该管道读取,则无法同步 cat
读取的数据wc
读取的数据。也就是说,wc
可能会直接从 ls
或 cat
读取数据。 cat
可能会从自身读取数据。 (这似乎有时会发生)。进程从管道读取数据的顺序将取决于它们被安排到 运行.
的顺序
您需要更多管道。 (比进程总数少一个。)
我有一些代码练习分叉进程(在命令行中模拟 (|))。但是,每次的输出都不一样。例如,对于 ./pipe ls cat wc
的输入,它应该与 ls | cat | wc
相同。但是,有时我的代码会输出
Child with PID 12126 exited with status 0x0.
Child with PID 12127 exited with status 0x0.
7 7 52
Child with PID 12128 exited with status 0x0.
但有时也会输出:
Makefile
pipe
#pipe.c#
pipe.c
pipe.o
README.md
test
Child with PID 12138 exited with status 0x0.
Child with PID 12139 exited with status 0x0.
0 0 0
Child with PID 12140 exited with status 0x0.
第一个输出是正确的(与ls | cat | wc
相比)。我发现通过第二个输出,程序 ls
和 cat
的管道输出没有被 wc
处理。我想知道我的程序出了什么问题,因为似乎我正确地设置了管道——第一个程序将从 stdin 获取输入并输出到管道的写入端,最后一个程序将从管道的读取端获取输入管道并输出到标准输出。感谢任何输入。
代码(./pipe
):
#include <stdio.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
int fd[2];
if (pipe(fd) == -1) {
int err = errno;
perror("pipe");
return err;
}
pid_t pid[argc-1];
int n = argc;
if(argc <= 1){
return EINVAL;
}
for (int i = 1; i < argc; i++){
if ((pid[i] = fork()) == -1){
int err = errno;
perror("fork");
return err;
}else if(pid[i] == 0){
//open(fd[1]);
if(i == 1){
dup2(fd[1],STDOUT_FILENO);
if (execlp(argv[i], argv[i], NULL) == -1) {
printf("failed to search for the provided executed program. \n");
return errno;
}
}else if(i == argc-1){
dup2(fd[0],STDIN_FILENO);
if (execlp(argv[i], argv[i], NULL) == -1) {
printf("failed to search for the provided executed program. \n");
return errno;
}
}else{
dup2(fd[0],STDIN_FILENO);
dup2(fd[1],STDOUT_FILENO);
if (execlp(argv[i], argv[i], NULL) == -1) {
printf("failed to search for the provided executed program. \n");
return errno;
}
}
}
close(fd[1]);
}
int wstatus;
pid_t pids;
while (n > 1) {
pids = wait(&wstatus);
printf("Child with PID %ld exited with status 0x%x.\n", (long)pids, wstatus);
--n;
}
}
您正在越界访问可变长度数组 pid
,因此您的程序具有 未定义的行为。
你可以通过将数组扩大一个元素来解决它:
pid_t pid[argc]; /* not argc - 1 */
另一个问题是你需要在每对命令之间建立一个新的管道。总的来说,一个管道少于命令的数量。也就是说,一个命令的管道为零。
stdin - ls - pipe - cat - pipe - wc - stdout // 3 commands, 2 pipes
这是一个想法,我在(几乎)循环的每次迭代中创建一个管道,并保存管道的输入端以供下一次迭代使用。我根本没有费心保存进程 id:s,也没有为 dup2
添加错误检查。但是,您应该检查它是否真的成功了。
#include <errno.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
int exec(const char* prog) {
if(execlp(prog, prog, NULL) == -1) {
perror("execlp");
}
return 1;
}
int main(int argc, char* argv[]) {
pid_t pid;
int in; // for saving the input side of the pipe between iterations
for(int i = 1; i < argc; ++i) {
int fd[2];
// must have at least 2 commands to create a pipe
// and we need one pipe less than the number of commands
if(argc > 1 && i < argc - 1) pipe(fd);
if((pid = fork()) == -1) {
perror("fork");
return 1;
} else if(pid == 0) {
if(i == 1) { // first command
if(argc > 1) { // must have more than one command to dup
dup2(fd[1], STDOUT_FILENO);
close(fd[1]);
close(fd[0]);
}
} else if(i == argc - 1) { // last command
dup2(in, STDIN_FILENO);
close(in);
} else { // middle commands
dup2(in, STDIN_FILENO);
close(in);
dup2(fd[1], STDOUT_FILENO);
close(fd[1]);
close(fd[0]);
}
return exec(argv[i]);
}
// parent
if(i > 1) close(in); // close old in
in = fd[0]; // save the stdin side of the pipe for next loop iteration
close(fd[1]); // no use for the stdout end
}
int wstatus;
while((pid = wait(&wstatus)) != -1) {
printf("Child with PID %ld exited with status 0x%x.\n", (long)pid,
wstatus);
}
}
您需要更多的管道,因为您当前的代码中只有一个。如果 ls
和 cat
都写入该管道,并且 cat
和 wc
都从该管道读取,则无法同步 cat
读取的数据wc
读取的数据。也就是说,wc
可能会直接从 ls
或 cat
读取数据。 cat
可能会从自身读取数据。 (这似乎有时会发生)。进程从管道读取数据的顺序将取决于它们被安排到 运行.
您需要更多管道。 (比进程总数少一个。)