3. Background
ï± Processes can execute concurrently
ï± May be interrupted at any time, partially completing execution
ï± Concurrent access to shared data may result in data inconsistency
ï± Maintaining data consistency requires mechanisms to ensure the orderly
execution of cooperating processes
ï± Illustration of the problem:
Suppose that we wanted to provide a solution to the consumer-producer
problem that fills all the buffers. We can do so by having an integer counter
that keeps track of the number of full buffers. Initially, counter is set to 0. It
is incremented by the producer after it produces a new buffer and is
decremented by the consumer after it consumes a buffer.
4. Producer
while (true) {
/* produce an item in next produced */
while (counter == BUFFER_SIZE)
; /* do nothing */
buffer[in] = next_produced;
in = (in + 1) % BUFFER_SIZE;
counter++;
}
5. Consumer
while (true) {
while (counter == 0)
; /* do nothing */
next_consumed = buffer[out];
out = (out + 1) % BUFFER_SIZE;
counter--;
/* consume the item in next consumed */
}
6. Race Condition
ï± A race condition is an undesirable situation that occurs when a
device or system attempts to perform two or more operations
at the same time, but because of the nature of the device or
system, the operations must be done in the proper sequence to
be done correctly.
ï± A race condition occurs when two or more threads can access
shared data and they try to change it at the same time.
8. Race Condition
ï± Processes P0 and P1 are creating child processs using the fork() system call
ï± Race condition on kernel variable next_available_pid which represents the next
available process identifier (pid)
ï± Unless there is mutual exclusion, the same pid could be assigned to two different processes!
9. Critical Section Problem
ï± Consider system of n processes {p0, p1, ⊠pn-1}
ï± Each process has critical section segment of code
ï± Process may be changing common variables, updating table, writing file,
etc
ï± When one process in critical section, no other may be in its critical section
ï± Critical section problem is to design protocol to solve this
ï± Each process must ask permission to enter critical section in entry
section, may follow critical section with exit section, then remainder
section
11. Solution to Critical-Section Problem
1. Mutual Exclusion - If process Pi is executing in its critical section, then no
other processes can be executing in their critical sections
2. Progress - If no process is executing in its critical section and there exist some
processes that wish to enter their critical section, then the selection of the
processes that will enter the critical section next cannot be postponed
indefinitely
3. Bounded Waiting - A bound must exist on the number of times that other
processes are allowed to enter their critical sections after a process has made
a request to enter its critical section and before that request is granted
ï Assume that each process executes at a nonzero speed
ï No assumption concerning relative speed of the n processes
12. Critical-Section Handling in OS
Two approaches depending on if kernel is preemptive or non-
preemptive
ï± Preemptiveâ allows preemption of process when running in
kernel mode
ï± Non-preemptive â runs until exits kernel mode, blocks, or
voluntarily yields CPU
ï± Essentially free of race conditions in kernel mode
13. Petersonâs Solution
ï± Not guaranteed to work on modern architectures! (But good algorithmic description
of solving the problem)
ï± Two process solution
ï± Assume that the load and store machine-language instructions are atomic; that is,
cannot be interrupted
ï± The two processes share two variables:
ï± int turn;
ï± boolean flag[2]
ï± The variable turn indicates whose turn it is to enter the critical section
ï± The flag array is used to indicate if a process is ready to enter the critical section.
flag[i] = true implies that process Pi is ready!
14. Algorithm for Process Pi
while (true){
flag[i] = true;
turn = j;
while (flag[j] && turn = = j)
;
/* critical section */
flag[i] = false;
/* remainder section */
}
15. Petersonâs Solution (contâd)
ï± Provable that the three CS requirement are met:
1. Mutual exclusion is preserved
Pi enters CS only if:
either flag[j] = false or turn = i
2. Progress requirement is satisfied
3. Bounded-waiting requirement is met
16. Petersonâs Solution
ï± Although useful for demonstrating an algorithm, Petersonâs Solution is
not guaranteed to work on modern architectures.
ï± Understanding why it will not work is also useful for better
understanding race conditions.
ï± To improve performance, processors and/or compilers may reorder
operations that have no dependencies.
ï± For single-threaded this is ok as the result will always be the same.
ï± For multithreaded the reordering may produce inconsistent or
unexpected results!
17. Petersonâs Solution
ï± Two threads share the data:
boolean flag = false;
int x = 0;
ï± Thread 1 performs
while (!flag)
;
print x
ï± Thread 2 performs
x = 100;
flag = true
ï± What is the expected output?
18. Petersonâs Solution
ï± 100 is the expected output.
ï± However, the operations for Thread 2 may be reordered:
flag = true;
x = 100;
ï± If this occurs, the output may be 0!
ï± The effects of instruction reordering in Petersonâs Solution
ï± This allows both processes to be in their critical section at the same time!