Laboratory Exercise on Concurrency in [Unix-based/GNU] C
Goals
This laboratory exercise provides some practice with beginning elements of
process control in Unix-based C programming, using the GNU C
compiler on MathLAN's PC/Linux computers.
Preparation
-
Review sample programs 1-3 in
An Introduction to Concurrency in Unix-based [GNU] C
Through Annotated Examples, as discussed in class.
Experiments with fork
-
Copy
~walker/c/concurrency-linux/fork-1.c to your account, compile it with
gcc and run it a few times -- waiting a few moments between each
run. How does the output differ for each run?
-
Add the statement sleep(10) between the two printf
statements for both the parent and the child process. (This will make each
process pause 10 seconds after the first printf before executing
the second printf.)
-
Again, compile and run the program in a terminal window.
-
Open a second terminal window. Now run the program in the first
terminal window. Then while it is running, type ps -ef in
the second terminal window. This second command gives a listing of
all processes running on your workstation. Toward the bottom of the
listing, you should see entries for both of the fork-1 processes.
-
In turn, change each sleep(10) statement to exit(1), and
repeat step 2. In other words, observe the process listing in each case
when one process exits abnormally while the other executes naturally.
-
If one process halts abnormally, does the other continue?
-
Does it matter in each case if exit(1) is replaced by
exit(0) -- for normal termination.
-
Insert the statement sleep(50) in only the child process,
between the two printf statements. Be sure no other
sleep or exit statements occur in the program (except the
exit(0) at the very end of the program).
Now, recompile and run the program.
-
After a few seconds, again use ps -ef in the second
terminal window to check the status of both processes.
-
When the prompt reappears in the original terminal window, try
executing some other commands (eg., ps or ls -l or
cat fork-1.c). Describe the results from these other commands.
What happened/happens to the child process fork-1 ?
-
What happens if the sleep(50) statement is placed only in the
parent process? How is this different from the sleep(50) in the
child process?
-
Does this experiment suggest any potential risks of spawning arbitrary
processes with fork? Explain.
-
Run the program containing sleep(50) (either for the parent or
the child) again. Now use ps -ef in the second
terminal window to find the process id's of a long-standing
process. Then use the statement
kill <process-id>
to terminate the execution of this process.
Note that the normal termination of a process may be accomplished
with
kill <process-id>.
In this case, a signal is sent to the process to stop the process. However,
in some cases, more drastic action is needed, and the statement
kill -KILL <process-id>
directs the operating system to do whatever is necessary to make the
process terminate.
Experiments with pipe
-
Copy
~walker/c/concurrency-linux/fork-2.c to your account, compile it with
gcc and run it a few times -- waiting a few moments between each
run.
-
In the statement write (fd[1], ...) change the 22 to 10. Then
recompile and rerun. How does this affect the running of the program?
Briefly explain what you see.
Now change the 10 (formerly 22) to 30 and rerun. Again, describe the
effect and explain why this happens.
-
In #define change MAX to 15, recompile and rerun.
Again describe and explain the result.
-
With MAX set to 15, change the reading/printing section of code for
the child to:
read(fd[0], line, MAX);
printf ("The string received is '%s'\n", line);
read(fd[0], line, MAX);
printf ("The string received is '%s'\n", line);
That is, perform the reading and printing twice. Rerun, describe, and
explain what happens.
-
With MAX set to 40, change the writing section of code for the
parent to:
write (fd[1], "ABCDEFGHIJKLMNOPQRSTUVWXYZ", 26);
write (fd[1], "abcdefghijklmnopqrstuvwxyz", 26);
At the same time, restore the code for the child to contain just one
read of line with a single corresponding printf.
Rerun, describe, and explain the result.
Local and Global Variables
-
Copy
~walker/c/concurrency-linux/fork-3.c to your account, compile it,
and run it. Why do you think the variable value is used in the
write statement rather than giving the number 20 directly?
-
Move the assignments
data_g = 10; /* change data elements */
data_l = 12;
from the beginning of the code for the parent process to the beginning of
the child's code segment. Recompile and rerun. Compare this output with
that from the previous step (step 12), and explain any differences.
-
Remove the wait statement from the parent. Then recompile and
rerun several times. Does the order of the output ever change? Explain
why or why not.
Work to be turned in
-
Answers for steps 2-5, 8-11, 12-14.
Note: For most steps, it is expected that the answer will be short.
This document is available on the World Wide Web as
http://www.cs.grinnell.edu/~walker/courses/201.sp05/lab-concurrency.shtml