我目前在以下練習中遇到問題:
我想ls | wc用下面的程式在 linux bash 中“模仿”管道命令列。我要做的是:
- 創建管道
- 創建一個 reader child 和 writer child
- writer child 關閉管道的讀取端并將其標準輸出重定向到管道的寫入端
- 讀者孩子關閉管道的寫入端并將管道的讀取端作為標準輸入
- 兩個孩子都執行 exec,撰寫器執行
ls程式,通過管道將輸出傳遞給在wc該輸出上執行程式的讀取器。
當我ls | wc在 linux 終端中執行時,我得到以下結果:
8 8 101
但是如果我執行我的程式,我會得到以下結果:
0 0 0
這是我的程式:
#include <stdlib.h>
#include <errno.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <sys/wait.h>
#include <libgen.h>
#include <signal.h>
#include <errno.h>
int main(void){
int mypipe[2];
pid_t pid1, pid2;
if (pipe(mypipe)<0)
perror ("pipe error"), exit(1);
if ((pid1=fork())<0)
perror ("fork error"), exit(1);
else if (pid1==0) {
//reader child
close (mypipe[1]);
if (dup2(mypipe[0], STDIN_FILENO)!=STDIN_FILENO)
perror ("dup2 error"), exit(1);
close (mypipe[0]);
if (execlp("wc", "wc", NULL)<0)
perror("execlp1 error"), exit(1);
else { //pid >0, parent
if ((pid2=fork())<0)
perror ("fork error"), exit(2);
else if (pid2==0) {
//writer child
close(mypipe[0]);
if (dup2(mypipe[1], STDOUT_FILENO) != STDOUT_FILENO)
perror("dup2 error"), exit(1);
close (mypipe[1]);
if (execlp("ls", "ls", NULL)<0)
perror ("execlp error"), exit(1);
}
else { //parent
close(mypipe[0]);
close(mypipe[1]);
waitpid(pid1, NULL, 0);
waitpid(pid2, NULL, 0);
exit(0);
}
}
}
return 0;
}
我究竟做錯了什么?提前感謝您的回答!
uj5u.com熱心網友回復:
你的代碼很混亂。您有許多不相關的標題,然后重復#include <errno.h>. 在main()函式中,您有:
int main(void)
{
int mypipe[2];
pid_t pid1, pid2;
if (pipe(mypipe) < 0)
perror("pipe error"), exit(1);
if ((pid1 = fork()) < 0)
perror("fork error"), exit(1);
else if (pid1 == 0)
{
// reader child
close(mypipe[1]);
if (dup2(mypipe[0], STDIN_FILENO) != STDIN_FILENO)
perror("dup2 error"), exit(1);
close(mypipe[0]);
if (execlp("wc", "wc", NULL) < 0)
perror("execlp1 error"), exit(1);
else // pid >0, parent
{
…
}
}
return 0;
}
該else if (pid1 == 0)子句由孩子執行。它關閉管道的寫入端,將讀取端復制到標準輸入并關閉管道的讀取端。然后它execlp()在wc. 只有當代碼執行失敗wc時,else子句才會被執行,然后只有管道的讀取端保持打開狀態。同時,原始行程簡單地退出。這將關閉管道,因此該wc命令沒有輸入,并0 0 0因此報告。
你需要重寫代碼。父行程應該等到它的兩個子行程都執行。尤其是在除錯的時候,千萬不要忽略children的退出狀態,要上報。
這是一些有效的代碼。請注意,它避免了濃密的決策樹——它是if/ else if/ ... /else代碼的線性序列。一般來說,這比一組復雜的、多層次的條件更容易理解。
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>
int main(void)
{
int fd[2];
pid_t pid1, pid2;
if (pipe(fd) < 0)
perror("pipe error"), exit(1);
else if ((pid1 = fork()) < 0)
perror("fork error"), exit(1);
else if (pid1 == 0)
{
/* ls */
dup2(fd[1], STDOUT_FILENO);
close(fd[0]);
close(fd[1]);
execlp("ls", "ls", (char *)0);
perror("exec ls");
exit(1);
}
else if ((pid2 = fork()) < 0)
perror("fork error"), exit(1);
else if (pid2 == 0)
{
/* wc */
dup2(fd[0], STDIN_FILENO);
close(fd[0]);
close(fd[1]);
execlp("wc", "wc", (char *)0);
perror("exec wc");
exit(1);
}
else
{
close(fd[0]);
close(fd[1]);
int status1;
int status2;
int corpse1 = waitpid(pid1, &status1, 0);
int corpse2 = waitpid(pid2, &status2, 0);
printf("ls: pid = %d, corpse = %d, exit status = 0x%.4X\n", pid1, corpse1, status1);
printf("ls: pid = %d, corpse = %d, exit status = 0x%.4X\n", pid2, corpse2, status2);
}
return 0;
}
在我的機器上運行該程式的示例pipe41生成:
$ pipe41
175 175 1954
ls: pid = 44770, corpse = 44770, exit status = 0x0000
ls: pid = 44771, corpse = 44771, exit status = 0x0000
$ ls | wc
175 175 1954
$
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/410341.html
標籤:
