Today’s topic • Inter-process communication with pipes

advertisement
Today’s topic
• Inter-process communication with pipes
• More about files and I/O.
– cin  read (0, …)
– cout  write (1, …)
– What happens when we use both I/O
mechanisms in the same program?
• Check out the output of mix.cpp?
– Why?
– The liberty in the implementation of the
C/C++ runtime library
• How to fix the order? fflush(0).
• More on the timestamp of a file
– How to get the info? Stat
– See newstat.c for comparing the timestamp of
two files.
• Inter-Process Communication (IPC):
– processes may be collaborated on tasks
– e.g,
ps -ef | grep a.out | more
– e.g,
client
server
– OS needs to provide mechanisms for IPC
• IPC related system calls:
– the most general IPC mechanism in UNIX is
socket (send and receive paradigm with
read/write interface, works also for processes on
different machines).
– What we will discuss:
• pipes: allow transfer of data between processes in a
first-in-first-out manner.
• signal: send a flag to another process
• Pipes:
– two types of pipes, named pipes and unnamed
pipes
– name pipes:
• like a file (create a named pipe (mknod), open,
read/write)
• can be shared by any number of processes
• will not be discussed in detail.
– Unnamed pipes:
• an unnamed pipe does not associated with any file
• can only be shared by related processes (descendants
of a process that creates the unnamed pipe).
• Created using system call pipe().
• Pipes and files
– Both can be used to share information among
processes
– Both share the file API
– Performance difference:
• A pipe is usually realized in memory, a file is not.
• Pipe operations are memory operations, file operations
are I/O operations.
– Semantic difference:
• A pipe is a fifo queue:
– The content in a fifo queue can only be read once (the
information is gone after the read operation).
• A storage in a file is persistent
– The content can be used many times.
• The pipe system call
– open unnamed pipes
– syntax
int pipe(int fds[2])
– semantic
create a pipe and returns two file descriptors fds[0] and
fds[1]
a read from fds[0] accesses the data written to fds[1] on
a fifo basis.
the pipe has a limited size (64K in most systems) -cannot write to the pipe infinitely.
#include <unistd.h>
#include <stdio.h>
main()
{
char *s, buf[1024];
int fds[2];
s = “hello world\n”;
pipe(fds);
write(fds[1], s, strlen(s));
read(fds[0], buf, strlen(s));
printf(“fds[0] = %d, fds[1] = %d\n”, fds[0], fds[1]);
write(1, buf, strlen(s));
}
/* example1.c */
#include <unistd.h>
#include <stdio.h>
main()
{
char *s, buf[1024];
int fds[2];
s = “hello world\n”;
pipe(fds);
if (fork() == 0) {
printf(“child process: \n”);
write(fds[1], s, 12); exit(0);
}
read(fds[0], buf, 6);
write(1, buf, 6);
}
/* example2.c : using pipe with fork*/
IPC can be used to enforce the order of the execution of processes.
main()
{
char *s, buf[1024];
int fds[2];
s = “hello world\n”;
pipe(fds);
if (fork() == 0) {
printf(“11111 \n”);
read(fds[0], s, 6);
printf(“22222\n”);
} else {
printf(“33333\n”);
write(fds[1], buf, 6);
printf(“44444\n”)
}
} /* example3.c */
11111
22222
33333
44444
33333
44444
11111
22222
11111 33333
33333 11111
22222 22222
44444 44444
/* how to make 111111 before 444444 */
• Anyone writes any programs that take
advantage of multi-core in a CPU?
– A multiple process solution for computing
PI?
• See pi1.c and pi2.c?
• Implementing Pipe in shell.
E.g.
/usr/bin/ps -ef | /usr/bin/more
• How shell realizes this command?
– Create a process to run ps -ef
– Create a process to run more
– Create a pipe from ps -ef to more
• the standard output of the process to run ps -ef is
redirected to a pipe streaming to the process to run
more
• the standard input of the process to run more is
redirected to be the pipe from the process running
ps -ef
• Implement “/bin/ps -ef | /bin/more” – first try
main() {
int fds[2];
char *argv[3];
pipe(fds);
// create pipe
if (fork() == 0) {
close(0); dup(fds[0]);
// redirect standard input to fds[0]
argv[0] = “/bin/more”; argv[1] = 0;
if (execv(argv[0], argv) == -1) exit(0);
} if (fork() == 0) {
close(1); dup(fds[1]);
// redirect standard output to fds[1];
argv[0] = “/bin/ps”; argv[1] = “-ef”; argv[2] = 0;
if (execv(argv[0], argv) == -1) exit(0);
}
wait(); wait();
} /* example4a.c */
• Example4a.c not the same as “/bin/ps –ef |
/bin/more”, what is missing?
– When can ‘more’ be done?
• When the end of the file is reached.
– What is “the end of file” of a pipe?
• No data in pipe?
• No data in pipe and no potential writer to the pipe!!!!
– In example4a.c, the more program will not finish
since there are potential writers.
• How to fix this program?
• Implement “/bin/ps -ef | /bin/more”
main() {
int fds[2];
char *argv[3];
pipe(fds);
// create pipe
if (fork() == 0) {
close(0); dup(fds[1]);
// redirect standard input to fds[1]
close(fds[0]); close(fds[1]); // close unused files
argv[0] = “/bin/more”; argv[1] = 0;
execv(argv[0], argv);
exit(0);
} if (fork() == 0) {
close(1); dup(fds[0]);
// redirect standard output to fds[0];
close(fds[0]); close(fds[1]); // close unused files
argv[0] = “/bin/ps”; argv[1] = “-ef”; argv[2] = 0;
execv(argv[0], argv);
exit(0);
}
close(fds[0]); close(fds[1]); wait(); wait();
} /* example4.c */
Download