Concurrency and Deadlock Flashcards
Concurrency and Deadlock
Problems with Concurrency
- The problem is simply sharing resources.
- Several threads/processes running at the same time.
- Using the same resources - accessing the same data
structures/objects/devices - Some resources can only be safely used by one thread at a time.
- e.g., readers accessing shared data while a writer is changing it
or writers changing a resource simultaneously
Race Concurrency
Any situation where the order of execution of threads can cause different results.
Critical Sections
- A piece of code in which we only want one thread to be active at a time.
- Providing this is known as mutual exclusion.
- We need:
1. a way of locking threads out of critical sections (should be as smallest possible)
2. to guarantee threads are not kept waiting forever - starvation - Starvation can be caused in different ways
- deadlock
- indefinite postponement - priority too low or just unlucky
Software Solution
- We want something like this:
lock
critical section
unlock - We have a Boolean variable locked which is true if the critical section is being
used by a thread. Initially locked is false. - Simple lock procedure:
while locked
end
locked = true
And the unlock:
locked = false
Peterson’s Algorithm
- The two processes share two variables:
flag = [false, false]
# both false initially
turn = 0 - turn indicates whose turn it is to enter the critical section
- flag[i] = true implies that process Pi is ready to enter the critical section
lock: performed by thread i; j is the other thread
flag[i] = true
turn = j
while (flag[j] && turn == j)
end
unlock: performed by thread i
flag[i] = false
Peterson’s Algorithm Properties
Two process solution
* Assume that the load and store machine-language instructions are atomic;
that is, cannot be interrupted
* Although useful for demonstrating an algorithm, Peterson’s Solution is not
guaranteed to work on modern architectures.
* To improve performance, processors and/or compilers may reorder
operations that have no dependencies
Hardware Support
- Many systems provide hardware support for implementing the critical section code.
- Uniprocessors – could disable interrupts
- Currently running code would execute without preemption
- Generally, too inefficient on multiprocessor systems
- Operating systems using this not broadly scalable
- We will look at two forms of hardware support:
1. Hardware instructions
2. Atomic variables
Hardware Instructions
testAndSet(lockVariable)
* returns the current value of the lockVariable
* and sets the lockVariable to true
* With this our lock can become
while (testAndSet(locked))
end
* unlock:
locked = false
TEST-AND-SET
- Or equivalent atomic or indivisible instructions
- they appear uninterruptible - once started no other process can interfere until
completed
COMPARE-AND-SWAP
- There are 3 parameters for a CAS operation:
1. A memory location V where value has to be replaced
2. Old value A which was read by thread last time
3. New value B which should be written over V
CAS Properties
- CAS says - V should have the value A; if it does, put B there. i.e., the swap takes place only under this condition.
- Executed atomically - guarantees that the new value is calculated based on up-to-date information; if the value had been updated by another thread in the meantime, the write
would fail.
Atomic Variables
Provides atomic (uninterruptible) updates
on basic data types such as integers and booleans.
Mutex Lock(Spinlock)
- Hardware solutions are complicated and generally inaccessible to application
programmers - OS designers build software tools to solve critical section problem
- Simplest is mutex lock
- Boolean variable indicating if lock is available or not
- Protect a critical section by
- First acquire() a lock
- Then release() the lock
- Calls to acquire() and release() must be atomic
- Usually implemented via hardware atomic instructions such as compare-and-swap.
- But this solution requires busy waiting
Semaphore
Synchronization tool that provides more sophisticated ways for
processes to synchronize their activities.
* Semaphore S – integer variable (count of how many of a certain resource are available)
* Can only be accessed via two atomic operations
* wait() and signal()
* Originally called P() and V()(or POSIX wait and post).
* Definition of the wait() operation
wait(S) {
while (S < 1)
; // busy wait
S–;
}
* Definition of the signal() operation
signal(S) {
S++;
}
* To get a resource the thread calls wait() on the semaphore.
To return the resource the thread calls signal().
* With semaphores we can solve various synchronization problems
Counting Semaphore
Integer value can range over an unrestricted domain