1 In Example 10.7, what would happen if a process that relinquished resource
failed to signal the event r_freed?
2 Sketch code, along the lines of Example 10.9, to implement a buffer with capacity for
n
data items, using the semaphores mutex, free_slots, and full_slots, initialized as follows:
sema_initialize(mutex, 1);
sema_initialize(free_slots, n);
sema_initialize(full_slots, 0);
3 A program contains many shared variables of the type T:
type
T
is
record
initialized : Boolean := false;
. . .
end record;
The programmer, worried about the inefficiency of semaphore operations, tries to initialize these variables safely,
without mutual exclusion, as follows:
procedure
initialize (v :
in out
T)
is
begin
if not
v.initialized
then
. . .
; -- give v its initial value
v.initialized := true;
end if;
end
initialize;
(a) Explain the race condition that prevents it from working reliably.
(b) Recognizing the mistake, the programmer does some research and learns about
double-checked locking, a technique that uses mutual exclusion only when necessary, and rewrites initialize as follows:
sema_initialize(mutex, 1);
. . .
procedure
initialize (v :
in out
T)
is
begin
if not
v.initialized
then
sema_wait(mutex);
if not
v.initialized
then
. . .
; -- give v its initial value
v.initialized := true;
end if;
sema_signal(mutex);
end if;
end
initialize;
Explain the programmer’s reasoning in thinking that this solves the mutual exclusion problem efficiently.
(c) Unfortunately, it actually fails to be safe. Explain why. What can be done to make it work reliably?