160 likes | 252 Views
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
E N D
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, • OS needs to provide mechanisms for IPC client server
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]; 11111 33333 11111 33333 int fds[2]; 22222 44444 33333 11111 s = “hello world\n”; 33333 11111 22222 22222 pipe(fds); 44444 22222 44444 44444 if (fork() == 0) { printf(“11111 \n”); /* how to make 111111 before 444444 */ read(fds[0], s, 6); printf(“22222\n”); } else { printf(“33333\n”); write(fds[1], buf, 6); printf(“44444\n”) } } /* example3.c */
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
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 */ • Implement “/bin/ps -ef | /bin/more” – first try
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?
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 */ • Implement “/bin/ps -ef | /bin/more”