Tom Kelliher, CS42
Sept. 18, 1996
Types of processes:
Reasons for design cooperating processes:
Two cooperating processes: producer, consumer.
Global data:
const int N = 10; int buffer[N]; int in = 0; int out = 0; int full = 0; int empty = N;
Producer:
while (1)
{
while (empty == 0)
;
buffer[in] = inData;
in = ++in % N;
--empty;
++full;
}
Consumer:
while (1)
{
while (full == 0)
;
outData = buffer[out];
out = ++out % N;
--full;
++empty;
}
Is there potential for trouble here?
Heavyweight process --- expensive context switch.
Thread:
Task: peer threads, shared memory and resources.
Can peer threads scribble over each other?
What about non-peer threads?
User-level threads:
Kernel-level threads:
How do threads compare to processes?
User-level threads multiplexed upon lightweight processes:

Basics: send(), receive() primitives.
Design Issues:
Resources owned by kernel.
Messages kept in a queue.
Assume:
Primitives:
Consider:
Process1()
{
...
S1;
...
}
Process2()
{
...
S2;
...
}
How can we guarantee that S1 executes before S2?
The situation:

Tape allocator process:
initialize();
while (1)
{
Receive(Tamb, message);
if (message is a request)
if (there are enough tape drives)
for each tape drive being allocated
{
fork a handler daemon;
send daemon mb # in message to requesting process;
update lists;
}
else
send a rejection message;
else if (message is a return)
{
update lists;
send an ack message;
}
else
ignore illegal messages;
}
Summary of user process actions: