Lecture 11

advertisement
Operating Systems
Lecture 11
UNIX Pipes
Read Handout
"An Introduction to Concurrency..."
4.1
File Redirection in UNIX
Everything in UNIX is a file.
Commands are files.
Pipes read and write to a buffer that is a file.
Many UNIX commands read and write to stdin and
stdout. These are also treated as files.
stdin has a special file descriptor: 0
stdout has a special file descriptor: 1
To redirect input or output we attach the file
descriptors for stdin or stdout to the file we want to
redirect the input (or output) to.
4.2
Steps for File Redirection
To redirect the input (or output) from stdin (or stdout) to
a file we must carry out the following steps:
1. Open the file for reading (or writing).
2. Attach the file descriptor for stdin (or stdout) to
the newly opened file.
3. Close the file descriptor for the opened file.
4.3
Opening a File
Use the command, open( ) to open a file for reading or
writing.
int fd;
// file descriptor
fd = open( fileName, FLAGS, permissions);
open( ) opens the file whose name is given by the string,
fileName, and returns an integer file descriptor to be used
to access the file.
fileName is a string, giving the name of the file.
FLAGS: a list of flags that indicate read/write status of file.
permissions: Indicates read/write permissions for the file
(only needed if creating a new
file).
4.4
FLAGS for open( )
The flags indicate the read/write status of the file:
O_RDONLY
Open the file for reading.
O_WRONLY
Open the file for writing.
O_CREAT
Create the file if it doesn't exist.
O_APPEND
Open the file for appending
O_TRUNC
Truncate the length of the file to zero.
Flags can be combined by a bitwise OR (|):
fd = open(myFile, O_WRONLY | O_APPEND);
Other flags are described on the man page for open.
4.5
File Permissions
File read/write permission can be indicated as a 3 digit
integer, with each digit indicating the permissions for the
user/group/others.
Each digit represents a 3 bit binary number, with each bit
representing read, write or execute permission.
1 indicates permission for that function
0 indicates no permission for that function
Example:
Permission:
rwxr-xr-111101100
7 5 4
fd = open(myFile, O_WRONLY | O_CREAT, 754);
4.6
Attaching the File Descriptor to stdin
(or stdout)
Use the function dup2( ) to attach the file descriptor for our
open file to stdin (or stdout):
dup2( fd, 0); // redirect stdin to file with descriptor fd
dup2( ) causes the second file descriptor (in this case the
descriptor for stdin) to refer to the same file as the first file
descriptor (in this case our open file).
To redirect to stdout, use dup2(fd, 1).
Once the input or output is redirected, you should close the
new file descriptor (it is no longer needed):
close(fd);
4.7
Example: Redirect Output
//The preliminaries
#include <iostream.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
int main(void) {
int cpid;
char myFile[20];
int myFileD;
int done, status;
4.8
Redirect output (continued)
cout << "Enter output file name: ";
cin >> myFile;
myFileD = open(myFile, O_WRONLY | O_CREAT | O_TRUNC, 0700);
cpid = fork( );
if (cpid == 0) {
//Child process
dup2(myFileD, 1);
//Attach stdout to file
close(myFileD);
//myFileD no longer needed
execlp("ls", "ls", "-l", NULL); //Execute ls command
} else {
//Parent process
done = wait(&status);
//wait for child to finish
cout << "All done!" << endl;
}
return 0;
}
Demo 1
4.9
Redirect input
cout << "Enter input file name: ";
cin >> myFile;
myFileD = open(myFile, O_RDONLY);
cpid = fork( );
if (cpid == 0) {
//Child process
dup2(myFileD, 0);
//Attach stdin to file
close(myFileD);
//myFileD no longer needed
execlp("wc", "wc", "-l", NULL); //Execute wc command
} else {
//Parent process
done = wait(&status);
//wait for child to finish
cout << "All done!" << endl;
}
return 0;
}
Demo 2
4.10
UNIX Pipes
Unix pipes allow communication between two processes
using a buffer.
One process writes to the buffer.
One process reads from the buffer.
The communication is unidirectional.
The buffer is accessed using a file descriptor.
(Recall that everything in UNIX is a file).
4.11
Creating a pipe
A pipe is represented by an integer array of length 2.
int fd[2];
fd[0]: file descriptor for reading from the pipe.
fd[1]: file descriptor for writing to the pipe.
Use the pipe( ) function to initialize the pipe:
pipe(fd);
(This should be done by the parent process).
To communicate using a pipe:
One process opens fd[0] (for reading) and closes fd[1].
The other process opens fd[1] (for writing) and closes fd[0].
4.12
#define MAX 25
int main(void) {
int cpid;
int fd[2];
char line[MAX];
int done, status;
pipe(fd);
cpid = fork( );
if (cpid == 0) {
cout << "The child process is active." << endl;
close(fd[1]);
//close writing end of pipe
read(fd[0], line, MAX); //read a max of 25 chars into line
cout << "The string received is " << line << endl;
} else {
cout << "The parent is active." << endl;
close(fd[0]);
//close reading end of pipe
write(fd[1], "Your parent is calling", 23); //write to pipe
done = wait(&status);
cout << "All done!" << endl;
}
return 0;
Demo 3
}
4.13
Using the pipes to redirect stdin and
stdout
In UNIX, pipes are often used to direct the output of one
command to the input of a second command.
Example:
who | wc -l
who normally directs the output to stdout. We want to
redirect the output to the writing end of the pipe.
wc normally reads input from stdin. We want to redirect
that input to come from the reading end of the pipe.
We redirect the input and output the same way we did for
file redirection.
4.14
Example: The first child
int main(void) {
int cpid, cpid2;
int fd[2];
int done, status;
pipe(fd);
cpid = fork( );
if (cpid == 0) {
cout << "The first child process is active." << endl;
close(fd[1]);
//close writing end of pipe
dup2(fd[0], 0); //redirect std in to reading end of pipe
close(fd[0]);
execlp("wc", "wc", "-l", NULL);
4.15
Example (cont'd): The second child
} else {
cpid2 = fork();
if ( cpid2 == 0){
cout << "The second child is active." << endl;
close(fd[0]); //close reading end of pipe
dup2(fd[1], 1); //redirect stdout to writing end of pipe
close(fd[1]);
execlp("who", "who", NULL);
4.16
Example (cont'd): The parent
} else {
cout << "The parent is active." << endl;
close(fd[0]); //close reading end of pipe
close(fd[1]); //close writing end of pipe
done = waitpid(cpid, &status, 0); //wait for children
done = waitpid(cpid2, &status, 0);
cout << "All done!" << endl;
}
}
return 0;
}
Demo 4
4.17
Download