Two Communicating Processes Hello Gunnar! Process Process CSCI 6730/ 4730 Chat Chat Maria Gunnar Operating Systems “ A ” “ B ” Hi Nice to Hear from you! Dup & Pipe ! Concept that we want to implement 2 Maria Hybinette, UGA Maria Hybinette, UGA On the path to communication… Review 1730 - File: The Unix Way ! Want: Comminicating processes ! One easy way to communicate is to use files. » We start with 2 » Process A writes to a file and process B reads from it ! Have so far: Forking – to create processes ! File descriptors ! Problem: » Mechanism to work with files » After fork() is called we end up with two independent » Used by low level I/O processes. – Open(), close(), read(), write() » Separate Address Spaces » file descriptors (the UNIX way) are generalized to ! Solution? How do we communicate? other communication devices such as pipes and sockets 3 4 Maria Hybinette, UGA Maria Hybinette, UGA Big Picture ( more on this later ) Pipe: Producer & Consumer ! Simple example: who | sort Stack Pointer » Both the writing process (who) and the reading Program Counter process (sort) of a pipeline that executes File Descriptor Table concurrently. ! A pipe is usually implemented as an internal fd 0 in File Table Entry OS buffer with 2 file descriptors. File status flags fd 1 out offet fd 2 » It is a resource that is concurrently accessed Vnode pointer fd 3 – by the reader and the writer, so it must be managed carefully (by the Kernel) PCB 5 6 Maria Hybinette, UGA Maria Hybinette, UGA
Buffering: Programming with Pipes Example: pipe-yourself.c write( p[1], msg1, MSGSIZE ); #include <stdio.h> write( p[1], msg2, MSGSIZE ); #include <unistd.h> #include <unistd.h> write( p[1], msg3, MSGSIZE ); int pipe( int fd[2] ); #define MSGSIZE 16 /* null */ for( i=0; i < 3; i++ ) { /* read pipe */ char *msg1= “ hello, world #1 ” ; read( p[0], inbuf, MSGSIZE ); ! pipe() binds fd[] to two file descriptors: char *msg2= “ hello, world #2 ” ; printf( “ %s\n ” , inbuf ); char *msg3= “ hello, world #3 ” ; } » fds[0] used to read from pipe return 0; {saffron:ingrid:4} pipe-yourself int main() hello, world #1 } » fds[1] used to write (stuff) to pipe { hello, world #2 char inbuf[MSGSIZE]; hello, world #3 ! Half-Duplex (one way) Communication User process int p[2], i; pipe p ! Returns 0 if OK and -1 on error. if( pipe( p ) < 0 ) fd[0] fd[1] { /* open pipe */ perror( “ pipe ” ); p[0] (read) exit( 1 ); process } p[1] (write) pipe 7 8 Kernel Maria Hybinette, UGA Maria Hybinette, UGA Things to Note What Happens After Fork? User Process (Parent) User Process (Child) User Process (Parent) ! Pipes uses FIFO ordering: first-in first-out . fd[0] fd[1] fd[0] fd[1] fd[0] fd[1] ! Read / write amounts do not need to be the same, but then text will be split differently. ! Pipes are most useful with fork() which Pipe Pipe creates an IPC connection between the parent and the child (or between the parents children) Before Fork After Fork ! Design Question: » Decide on : Direction of data flow – then close appropriate ends of pipe (at both parent and child) 9 10 Maria Hybinette, UGA Maria Hybinette, UGA Example: Parent Writes/Child Reads pipe-fork-close.c if( pid > 0 ) /* parent */ { #include <stdio.h> ! A forked child close( p[0] ); /* read link */ #include <sys/wait.h> #include <unistd.h> write( p[1], msg1, MSGSIZE ); » Inherits file descriptors from its parent #define MSGSIZE 16 write( p[1], msg2, MSGSIZE ); write( p[1], msg3, MSGSIZE ); ! pipe() char *msg1= “ hello, world #1 ” ; wait( (int *) 0 ); if( pid == 0 ) /* child */ char *msg2= “ hello, world #2 ” ; } » Creates an internal system buffer and two file { char *msg3= “ hello, world #3 ” ; close( p[1] ); /* write link */ descriptors, one for reading and one for writing. for( i=0; i < 3; i++ ) int main() { ! After the pipe call, { read( p[0], inbuf, MSGSIZE ); char inbuf[MSGSIZE]; printf( “ %s\n ” , inbuf ); int p[2], i, pid; » The parent and child should close the file } } descriptors for the opposite direction (that it if( pipe( p ) < 0 ) return 0; } { /* open pipe */ doesn’t need). perror( “ pipe ” ); exit( 1 ); p[0] (close read) » Leaving them open does not permit full-duplex } if( (pid = fork()) < 0 ) communication. { parent child perror( “ fork ” ); exit( 2 ); } 11 12 p[1] (close write) Maria Hybinette, UGA Maria Hybinette, UGA
Some Rules of Pipes Pipes and exec() How can we code who | sort ? ! Every pipe has a size limit » POSIX minimum is 512 bytes -- most systems makes this figure larger Observation: Writes to stdout and reads from stdin. ! read() blocks if pipe is empty and there is a a write link open to that pipe [it hangs] 1. Use exec() to ‘run’ code in two ! read() from a pipe whose write() end is closed and is processes (one runs who [child] and the empty returns 0 (indicates EOF ) [but it doesn’t hang] other sort [parent] ) which share a » Lesson Learned: pipe (exec in child starts a new program – Close write links or read() will never return ***** within a copy of the ‘ parent ’ process). ! write() to a pipe with no read() ends returns -1 and generates SIGPIPE and errno is set to EPIPE 2. Connect the pipe to stdin and stdout ! write() blocks if the pipe is full or there is not enough using dup2(). room to support the write(). » May block in the middle of a write() 13 14 Maria Hybinette, UGA Maria Hybinette, UGA Dup2 Duplicate File Descriptors ! Duplicate a pipe file descriptor to stdin or #include <unistd.h> stdout (whichever is appropriate), e.g., int dup2( int old-fd, int new-fd ); ! Set one FD to the value of another. » dup2(pipefd, stdin), or ! new-fd and old-fd now refer to the » dup2(pipefd, stdout) new-fd same file old fd ! Now processes connected to pipe can ! if new-fd is open [before copied over], read and write like it is from stdin and it is first automatically closed File stdout ! Note that dup2() refer to fds not » Caveat: Beware of hanging on the ‘pipe’ streams – Solution: Close all file descriptors that comprise its pipes ! Example: so that the pipes don't hang. » dup2( fd[1], fileno(stdout)); Pipeline.c 15 16 Maria Hybinette, UGA Maria Hybinette, UGA Example : sort < file1.txt | uniq Want: sort < file1.txt | uniq ! What does this look like? How would a shell Parent uniq Child sort be programmed to process this? stdin fd[0] stdin fd[0] stdout fd[1] stdout fd[1] » Well we know we need a parent & child to communicate though the pipe! » Parent File 1 » Child Pipe » We need to open a file and read from it – and then read it as we read it from standard input. ! Want: How do we get there? 17 18 Maria Hybinette, UGA Maria Hybinette, UGA
Want: “ sort < file1 | uniq ” Want: “ sort < file1 | uniq ” Parent Parent filedes filedes stdin fd[0] stdin fd[0] stdout fd[1] stdout fd[1] File 1 File 1 fileDES = open( ” file1.txt", O_RDONLY ); � fileDES = open( "myfile.txt", O_RDONLY ); � dup2( fileDES, fileno( stdin) ); � 19 20 Maria Hybinette, UGA Maria Hybinette, UGA Want: “ sort < file1 | uniq ” Want: “ sort < file1 | uniq ” Parent Parent filedes filedes stdin fd[0] stdin fd[0] stdout fd[1] stdout fd[1] File 1 File 1 Pipe fileDES = open( "myfile.txt", O_RDONLY ); � pipe( fd ); � dup2( fileDES, fileno( stdin) ); � … fork() … � close( fileDES ); � 21 22 Maria Hybinette, UGA Maria Hybinette, UGA Want: “ sort < file1 | uniq ” Want: “ sort < file1 | uniq ” Parent Parent uniq Child Child sort filedes filedes stdin fd[0] stdin fd[0] stdin fd[0] stdin fd[0] stdout fd[1] stdout fd[1] stdout fd[1] stdout fd[1] File 1 File 1 Pipe Pipe fork(); � fork(); � /* decide who does what */ /* now do the plumbing */ � 23 24 Maria Hybinette, UGA Maria Hybinette, UGA
Recommend
More recommend