我的任務是在 c 中創建自己的 shell。我將使用 fork()、pipe()、exec() 和 wait() 來實作這一點。我有一個好的開始,但是我對管道的研究越多,我就越困惑。管道到子行程的每個示例如下所示:

我完全理解這一點。我之前已經實作過。我的問題是這個例子有多簡單。在創建 shell 時,我需要兩個孩子通過管道相互通信,以便運行像“cat file | grep hello”這樣的命令。我可以想象有幾種方法可以做到這一點。這是我的第一個想法:

This doesn't seem to work. I could just be that my code is flawed, but I suspect my understanding of pipes and file descriptors is insufficient. I figured that since pipe was called in main() and fd[] is a file variable, this strategy should work. The Linux manual states "At the time of fork() both memory spaces have the same content." Surely my child processes can access the pipe through the same file descriptors.
Is there a flaw in my understanding? I could try to make the processes run concurrently like so:

But I'm not sure why this would behave differently.
Question: If a process writes to a pipe, but there is no immediate second process to read that data, does the data get lost?
Most examples online show that each process needs to close the end of the pipe that it is not using. However, occasionally I see an example that closed both ends of the pipe in both processes:
close(fd[1]);
dup2(fd[0], STDIN_FILENO);
close(fd[0]);
As best I can tell, dup2 duplicates the file descriptor, making 2 open file descriptors to the same file. If I don't close BOTH, then execvp() continues to expect input and never exits. This means that when I am done with the reading, I should close(stdin).
Question: With 2 children communicating over a pipe, does the main process need anything with the pipe, such as close(fd[0])?
uj5u.com熱心網友回復:
如果一個行程寫入管道,但沒有立即讀取該資料的第二個行程,資料會丟失嗎?
不。
默認情況下,寫入管道是一個阻塞操作。也就是說,寫入管道將阻止呼叫行程的執行,直到管道中有足夠的空間來寫入請求的資料。
讀取端的責任是排空管道以騰出空間,或者關閉管道的一側以表示他們不再希望接收資料。
有 2 個孩子通過管道進行通信,主行程是否需要管道的任何內容,例如 close(fd[0])?
涉及的每個行程都有自己的檔案描述符副本。
因此,父行程應該關閉管道的兩端(在兩個分叉之后),因為它沒有理由保留這些檔案描述符。不這樣做可能會導致父行程用盡檔案描述符 ( ulimit -n)。
你的理解dup2似乎是正確的。
close(fd[1]);
dup2(fd[0], STDIN_FILENO);
close(fd[0]);
管道的兩端都是關閉的,因為dup2通常與now 關聯的檔案描述符與管道讀取端的檔案描述符所stdin參考的檔案描述相同。
stdinexec*當替換程序映像( )退出時,當然是關閉的。
您對兩個同時運行的行程進行分叉的第二個示例是正確的理解。
在典型的 shell 中,管道命令同時運行。否則,如前所述,作者可能會在完成其任務之前填充管道并阻塞。
通常,父行程等待兩個行程完成。
這是一個玩具示例。運行為./program FILE STRING模擬cat FILE | grep STRING。
#include <stdio.h>
#include <sys/wait.h>
#include <unistd.h>
int main(int argc, char **argv) {
int fds[2];
pipe(fds);
int left = fork();
if (0 == left) {
close(fds[0]);
dup2(fds[1], fileno(stdout));
close(fds[1]);
execlp("cat", "cat", argv[1], NULL);
return 1;
}
int right = fork();
if (0 == right) {
close(fds[1]);
dup2(fds[0], fileno(stdin));
close(fds[0]);
execlp("grep", "grep", argv[2], NULL);
return 1;
}
close(fds[0]);
close(fds[1]);
waitpid(left, NULL, 0);
waitpid(right, NULL, 0);
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/440890.html
