Reputation: 16502
I'm trying to understand the usage of pipe.
A parent process will pipe and if the parent forks, the child process will inherit the pipe. So now we hae a direct link to the child process and they can communicate?
I get lost when we start to close pipes and redirect pipes. Does anyone have a good explanation on closing pipes and redirecting pipes?
Thank you in-advance.
Upvotes: 4
Views: 2808
Reputation: 8933
Here's the deal.
Here is what it looks like:
P1=[WR FD]===========[RD FD]=[STDIN]=P2
P1=[RD FD]===========[WR FD]=[STDOUT]=P2
P1 and P2 are processes. And "===" depict the pipes.
Your question was specifically about closing and redirecting. That comes into play when you perform the switch I referred to earlier. Let's say you have obtained a pipe by using the pipe() system call.
int fd[2];
pipe(fd);
Now you create a child process, and in that process perform the switch, like so:
if (!fork()) // 0 return value indicates that you are in the child process
{
dup2(fd[0], 0); // dup2 first closes 0 in the child process, then duplicates
// fd[0] as 0; keep in mind that 0 is stdin and fd[0] is the
// read end of the pipe
exec(something); // start the new process, which when it reads stdin, will be
// reading the pipe instead
}
Upvotes: 6
Reputation: 11220
We often use a pipe. As says Amardeep, the child process inherits the parent's descriptor, including pipe.
Here is an example for 2 commands. I'm not sure of my algorithm for n commands :-)
void do__pipe(char** cmd1, char** cmd2)
{
int fd[2]; /* fd[0] for reading fd[1] for writting */
if (pipe(fd) == -1)
{
perror("pipe");
}
switch (fork())
{
case -1:
perror("fork"); exit (1);
case 0:
close (fd[0]);
dup2 (fd[1], STDOUT_FILENO);
close (fd[1]);
execvp (cmd1[0], cmd1);
exit (1);
}
dup2(STDIN_FILENO, STDIN_FILENO);
switch (fork())
{
case -1:
perror("fork (2)"); exit (1);
case 0:
close (fd[1]);
dup2 (fd[0], STDIN_FILENO);
close (fd[0]);
execvp (cmd2[0], cmd2);
exit (1);
}u
wait((int*)NULL);
}
this code has been taken from a small shell I had to write for my studies, so char** cmd1 would be something like ["cat", "/etc/passwd"] and cmd2 could be ["wc", "-l"]
Upvotes: 1
Reputation: 95684
See Pipeline.
Simple example
ls -l | less
In this example, ls is the Unix directory lister, and less is an interactive text pager with searching capabilities. The pipeline lets the user scroll up and down a directory listing that may not fit on the screen.
Creating pipelines programmatically
Pipelines can be created under program control. The Unix
pipe()
system call asks the operating system to construct a new anonymous pipe object. This results in two new, opened file descriptors in the process: the read-only end of the pipe, and the write-only end. The pipe ends appear to be normal, anonymous file descriptors, except that they have no ability to seek.To avoid deadlock and exploit parallelism, the Unix process with one or more new pipes will then, generally, call
fork()
to create new processes. Each process will then close the end(s) of the pipe that it will not be using before producing or consuming any data.
Upvotes: 4
Reputation: 19064
The child process inherits the parent's open descriptors. Default ones are stdin, stdout, stderr. They do not provide a means for the child to communicate directly with the parent since they actually go to the console. So typically you close or redirect those so you don't pollute the parent's console I/O.
But if you have a pair of pipes open you can use their descriptors as inherited by the child to communicate both ways between the two processes. Use one descriptor per direction.
Upvotes: 1
Reputation: 12392
You use the dup
family of system calls to change a new file descriptor to one of the first three system calls.
int new_stdout = open("filename", O_WRONLY);
/* ... error check ... */
if (!fork()) {
/* in child */
dup2(new_stdout, 1);
execve("program", argv, envp);
This makes "filename" write its standard out to "filename".
Upvotes: 3