Principles of Concurrency
Consider two processes P1 and P2 executing the function
echo:
Void echo()
{
chin=getchar();
chout = chin;
putchar(chout);
}
• One character is read from the keyboard one keystroke at a time, stored
in variable chin.
•And sent out to the screen for display.
Let’s assume, two overlapping processes P1 and P2 use simple routine.
Process P1 Process P2
. .
chin=getchar(); .
. chin=getchar();
chout=chin; chout=chin;
putchar(chout); .
. putchar(chout);
P1’s input is lost; for both P1 and P2 the same character is sent to the screen.
Race Condition
Race condition: The situation where several
processes access – and manipulate shared
data concurrently. The final value of the
shared data depends upon which process
finishes last.
To prevent race conditions, concurrent
processes must be synchronized.
Race Conditions
Example:
Process A wants to write
to the directory, 7 read into
its local variable
Interrupt
Process B reads in 7,
writes to slot 7, updates in
to 8
Process A resumes, also
writes to slot 7 and updates
it to 8
Two processes want to access
shared memory at the same time.
Race condition
Two or more processes are reading and writing some shared
data and the final result depends on the order in which they run
To avoid this kind of situation, we require some form of
synchronization of the processes
Mutual exclusion: preventing more than one process from using
the shared memory at the same time.
Mutual exclusion problem
Successful use of concurrency among processes
requires the ability to define critical sections and
enforce mutual exclusion.
Critical section : is that part of the process code
that affects the shared resource.
Mutual exclusion: in the use of a shared
resource is provided by making its access
mutually exclusive among the processes that
share the resource.
•This is also known as the Critical Section (CS)
problem.
Critical Regions (2)
Mutual exclusion using critical regions.
Mutual exclusion
Any facility that provides mutual exclusion should meet
these requirements:
1. No assumption regarding the relative speeds of the
processes.
2. A process is in its CS for a finite time only.
3. Only one process allowed in the CS.
4. Process requesting access to CS should not wait indefinitely.
5. A process waiting to enter CS cannot be blocking a process in
CS or any other processes.
Solution to mutual exclusion
Shared lock variable:
0: process sets it to 1, then enters the critical region,
re-set it to 0 when leaving
1: process just waits
– Suffers the same problem (race condition)
– P0 sees 0, before setting it to 1, blocked.
– P1 see 0, sets it to 1, enters critical region
– P0 resumes, sets it to 1, enters critical region
– Now two processes are in their critical regions accessing the
same shared memory
The TSL Instruction (1)
atomic
. Entering and leaving a critical region using the TSL
instruction.
The Producer-Consumer Problem
...
The producer-consumer problem with a fatal race condition.
Race condition
Problem with count
Buffer empty
Consumer sees count = 0
Producer executes, inserts to buffer, increase count to
1, wakes up consumer
Consumer not asleep yet, wakeup signal lost
Consumer executes, sleeps (since count = 0 for him)
……
Producer fills the buffer, sleeps
Now both sleep
Semaphores
•A semaphore is a special kind of integer variable,
usually stored in shared memory, so all processes can
access it.
•It is used as a flag that is only accessed through two
atomic operations: down and up.
PROPERTIES:
Machine independent: no need to code at assemble level as
in tsl.
Works with any no of processes.
Can have different semaphores for different critical sections.
A process can acquire multiple needed resources by
executing multiple downs.
Simply binary semaphore or more than one if desired using a
counting semaphore.
Semaphore Implementation
•Define a semaphore as a class:
class Semaphore
{ int value; // semaphore value
ProcessQueue L; // process queue
//operations
Wait();
Signal();
}
•In addition, two simple utility operations:
–block() suspends the process that invokes it.
–Wakeup() resumes the execution of a blocked
process P.
Semantics of wait and signal
•Semaphore operations now defined as
[Link]():
[Link]--;
if ([Link] < 0) {
add this process to S.L;
block(); // block a process
}
[Link]():
[Link]++;
if ([Link] <= 0) {
remove a process P from S.L;
wakeup(); // wake a process
}
Semaphores for CS
• Semaphore is initialized to 1. The first process that
executes a wait() will be able to immediately enter
the critical section (CS). ([Link]() makes S value zero.)
• Now other processes wanting to enter the CS will
each execute the wait() thus decrementing the value
of S, and will get blocked on S. (If at any time value of
S is negative, its absolute value gives the number of
processes waiting blocked. )
• When a process in CS departs, it executes [Link]()
which increments the value of S, and will wake up
any one of the processes blocked. The queue could
be FIFO or priority queue.
Two Types of Semaphores
•Counting semaphore – integer value can
range over an unrestricted domain.
•Binary semaphore – integer value can
range only between 0 and 1; can be
simpler to implement. ex: nachos
•Can implement a counting semaphore
using a binary semaphore.
Semaphores (new variable type)
down (S) { up (S) {
while (S <= 0) ; S++;
S--; }
}
Both operations are atomic (indivisible)
Note: there are many different names for these two operations
down: wait, semWait, P (Proberen)
up: signal, semSignal, V (Vergogen)
MUTEX
• Short form for “Mutual exclusion object.”
• Allows multiple threads for sharing the same
resource. The resource can be a file.
• A mutex must be locked from other threads,
when any thread that needs the resource;
when the data is no longer used/needed, the
mutex is set to unlocked ‘only by the thread
that locked it’; thus it has ownership concept.
Mutexes
Implementation of mutex lock and mutex unlock.
The Producer-Consumer Problem
...
The producer-consumer problem with a fatal race condition.
Producer & Consumer: Semaphores
...
The producer-consumer problem using semaphores.