thanks in advance for any help.
I am trying to replicate the behavior of the shell command ls -1 /usr/include | more
ls -1 /usr/include | more
using a C program. I wrote this code:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main(){
int page[2]; // page is the name of my pipe
pipe(page);
switch (fork()){
case -1:
exit(1);
break;
case 0:;
close(page[1]);
dup2(page[0], 0);
close(page[0]);
execlp("more", "more", NULL);
default:
close(page[0]);
dup2(page[1], 1);
close(page[1]);
execlp("ls", "ls", "-1", "/usr/include", NULL);
break;
}
}
But it only prints one page (as more
would do) and causes some weird behavior that blocks my terminal (forcing me to use reset
to set it back to normal).
I just realized the roles of the parent and the child process were being mixed up. The one to run the more
command should be the parent. Since more
is an interactive command, the terminal will respond better to it as the parent (I'm guessing).
So to solve my issue, I switched the roles of the parent and the child.
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main(){
int page[2]; // page is the name of my pipe
pipe(page);
switch (fork()){
case -1:
exit(1);
break;
case 0:;
close(page[0]);
dup2(page[1], 1);
close(page[1]);
execlp("ls", "ls", "-1", "/usr/include", NULL);
break;
default:
close(page[1]);
dup2(page[0], 0);
close(page[0]);
execlp("more", "more", NULL);
}
}
WHY DOES THIS SOLVES THE PROBLEM? (I still do not clearly understand why it worked!)
Your original code creates a kind of a race condition between the parent and the child processes, and the shell which started your program. The ls
process ends before more
can read all the data from the pipe, and since in your program the parent process is replaced by the ls
process, when that ls
process ends (after writing all its output into the pipe buffer) it exits, and in doing so closes the pipe and gives control back to the shell which will immediately get ready to read another command.
So, initially both more
and the shell may be reading from the same TTY device (it's reading from its STDERR
descriptor, still attached to your TTY), and then once more
eventually gets some input it will try to read from the pipe again (its STDIN
) and it will get an end-of-file (the pipe has been closed on the write end by the exit of ls
), and so more
will now also exit (without printing any more output). There's also a possible race between the more
process and the shell as to which (re)sets the TTY driver modes and when.
An alternative implementation of your program is for the original parent process to start two child processes, one for more
and one for ls
, and then to wait for both processes to terminate, but this will of course require more system resources.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.