Homework: processes and threads

This lecture covers scheduling policies of threads and processes. Recall that a process is an abstraction which includes a program counter, registers, and an address space which includes the code, static data, stack and the heap. Threads are abstractions similar to processes except that multiple threads can share the same address space. Each thread has it's own program counter, registers and stack. Threads can share code, static data, and heap. Threads take significantly less space than processes because they don't require separate address spaces.

Hand-In Procedure

You are to turn in this homework during lecture. Please write up your answers to the exercises below and hand them in to a staff member at the beginning of lecture. Mention your CSE login ID at the top of your homework submission.

Assignment Part 1 (Processes)

On a linux machine, type the following command (we will see more details about processes, just like we saw in previous homework).
$ cat | tee output.file

Turn in: While this command is running, examine the processes created:

Assignment Part 2 (Threads)

Threads can be implemented completely at the user level. i.e., we do not require privileged operations to implement a thread abstraction and schedule different threads. In other words, a process can provide multiple threads by implementing a scheduler. Let's see how this can be done.

To implement threads, the process needs to provide the abstraction of multiple control-flow (program counter), multiple register sets and multiple stacks. This can be done if after every periodic time interval, one thread can be interrupted and saved and another thread can be loaded. Saving a thread involves saving it's program counter, registers and stack pointer. Similarly, loading a thread involves loading the new thread's program counter, registers and stack pointer. Neither the save operation, nor the load operation requires any privileged operation -- we are just loading and saving registers.

So the only remaining issue is how to periodically interrupt a running thread from within a process. For an OS, this interruption is done by the hardware timer device. A process can do this using the SIGALRM signal.

Such threads implemented inside a process are called user-level threads. The OS cannot distinguish between multiple user-level threads and it can only see one process that is running which includes the thread scheduler and the different threads.

Turn in:
Read the manpage of the signal, alarm, and setitimer. Understand how SIGALRM can help in implementing user-level threads. Briefly describe how you will do this (2-3 sentences and some pseudo-code).

Assignment Part 3 (Zombies)

In UNIX, a child process may terminate before a parent calls wait(). When the parent calls wait() eventually, it still expects to read the correct exitcode that the child returned. To support this functionality, UNIX does not completely remove the process till it's parent has called wait() on it.

Such processes that have completed execution but still have an entry in the process table are called zombie processes. Usually, the presence of zombie processes in the system for a long time indicates a bug in the program (it is a common error).

Read about Zombie process at this wikipedia article. Also read about the SIGCHLD signal.

Turn in:
In class we discussed that the shell implements "&" functionality by not calling wait() immediately. Should the shell never call wait()? When should it call wait()? Answer by providing short pseudo-code.