CMPS 3600 Lab 11 - Unix Pipes

Goals

resources:

Review the pipe manpages in the /examples/b/man directory. Then copy these files into your directory:

     $ cd
     $ cd 3600/b
     $ cp /home/fac/gordon/public_html/3600b/examples/b/*.c .
     $ cp /home/fac/gordon/public_html/3600b/examples/b/Makefile .

     You may copy all the sample file if you like.

dotprod.c uses four threads to compute the dot product of two integer vectors. Your job is to modify the program to incorporate a pipe. You will use the pipe to communicate between the threads and a forked child.
Copy dotprod.c to rvlab11.c and add an entry to the Makefile.
$ cp dotprod.c rvlab11.c
Fix your Makefile to build rvlab11.c

You are going to add a fork to your code. Make sure that you open the pipe before the fork. The child's job is to read from the pipe, blocking until something is sent down the pipe. Meanwhile, the parent spawns the threads. Each thread writes its result to the pipe. The child reads the results from the pipe, sums the results and displays the result on the screen. If all goes well you will see the sum of 1+2+3+ ... +518+519+520.

A note about pipes. They are very low level. Pipes use the write command to stuff data into the pipe and the read command to grab data from the pipe. It is up to you to know what format the stuff that you read and write is expected to be in. If you send integers you need to know an int is four bytes. Then you can do this:

      int out = 25;
      write(mypipe, &out, 4);
      int in;
      read(mypipe, &in, 4);

If you are careful you will need to modify very little of the dotprod.c code. Create a global set of file descriptors for the pipe (one is for the incoming end and one for the outgoing end):
     int pipefd[2];  /* give your file descriptors a name you like */

     A child process inherits file descriptors from the parent.
     A pipe has 2 file descriptors, the read end and the write end.
Before the fork open the pipe:
     pipe(pipefd);
Insert the code to read and write in the correct spots in parent and child. The threads will write to the parent's end of the pipe. Follow this diagram:
    ----------------                               ---------------
     PARENT PROCESS                                 CHILD PROCESS 
    ----------------                               ---------------
    close(pipefd[0])                               close(pipefd[1]) 
    
      [Outgoing End]     /-------------------\    [Incoming End]
    write(pipefd[1]) ==>     >>  data >>       ==> read(pipefd[0])  
    close(pipefd[1])         >> EOF  >>       
                         \-------------------/

Use pipetest.c as an example.

The outgoing end pipefd[1] behaves like stdout; i.e., the threads write to it. The incoming end pipefd[0] behaves like stdin; i.e., the child reads from it.

Note: pipes are IPC only - you should not use a pipe to communicate between threads of the same process.

Clarification of this lab... 1. You are given a program that works. Portions of a dot-product are summed inside of threads. The summing will no longer be done in the threads. Comment out this line in your thread function: /* dotstr.total += localsum; */ Do not remove the line of code. Comment it out. <----- Write localsum to your pipe, instead. There is no longer a need for dotstr.total in the program. You must comment it out... typedef struct { int *a; int *b; /* int total; */ int veclen; } Dotdata; Do not remove the line, rather comment it out. <----- Declare a local variable within the scope of the child process to sum the dot-product components. Create a variable name that helps to self-document your program, and a name that you think will be unique among all the lab programs written by students in our class. 2. The parent process will create and control the threads, but will no longer display the final dot-product. Comment this line out: /* printf ("the dot product sum: %d\n", dotstr.total); */ Instead, write a line of code in your child process that will display the final dot-product value. 3. The child process will now do the summing of the dot-product components. It is accomplished by reading all the component values that come out of the read-end of the pipe. The child process will display the dot-product to the screen. Notes: The test run using strace is not usually performed by your instructor during grading of an assignment. The Linux manpage for pipe(2) is a great source for this lab.

Sample runs:


$ ./lab11
Child process sum from pipe: 143916
Child's exit code: 0


$ strace -f -e trace=pipe,read,write,close ./lab11 2>out
$ cat out

close(3)                                = 0
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>
\0\1\0\0\0@\\\0\0\0\0\0\0"..., 832) = 832
close(3)                                = 0
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>
\0\1\0\0\0\300\357\1\0\0\0\0\0"..., 832) = 832
close(3)                                = 0
pipe([3, 4])                            = 0
Process 1691 attached
[pid  1688] close(3)                    = 0
Process 1692 attached
Process 1693 attached
Process 1694 attached
Process 1695 attached
[pid  1692] write(4, "\272\23\0\0", 4)  = 4
[pid  1692] close(3)                    = 0
[pid  1692] read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>
\0\1\0\0\0p.\0\0\0\0\0\0"..., 832) = 832
[pid  1692] close(3)                    = 0
Process 1692 detached
[pid  1691] close(4)                    = 0
[pid  1691] read(3, "\272\23\0\0", 4)   = 4
[pid  1691] read(3,  <unfinished ...>
[pid  1694] write(4, "\332a\0\0", 4)    = 4
[pid  1693] write(4, "\312:\0\0", 4)    = 4
Process 1694 detached
[pid  1691] <... read resumed> "\332a\0\0", 4) = 4
[pid  1691] read(3, "\312:\0\0", 4)     = 4
Process 1693 detached
[pid  1691] read(3,  <unfinished ...>
[pid  1695] write(4, "\352\210\0\0", 4) = 4
[pid  1691] <... read resumed> "\352\210\0\0", 4) = 4
[pid  1691] read(3, Process 1695 detached
 <unfinished ...>
[pid  1688] close(4 <unfinished ...>
[pid  1691] <... read resumed> "", 4)   = 0
[pid  1688] <... close resumed> )       = 0
[pid  1691] write(1, "Child process sum from pipe: 143916\n", 29) = 29
[pid  1691] close(3)                    = 0
Process 1691 detached
--- SIGCHLD (Child exited) @ 0 (0) ---
write(1, "Child's exit code: 0\n", 21)  = 21

Files due at 12:30pm...

     3600/b/rvlab11.c 
     3600/b/Makefile