End of Midterm Material Flashcards
Race Condition
Two or more processes accessing the same shared data at the same time and outcome depends on the order of execution.
Critical-Section Problem Solution (3)
- Mutual Exclusion - If process Pi is executing in its critical section, then no other processes can be executing in their critical sections
- 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
- 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
Critical-Section Handling in OS (2)
Preemptive – allows preemption (removed & replaced - interrupted) 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
Critical-Section Problem Solutions
Hardware & Software options
Hardware 1. Test & lock 2. Swap Software 1. Peterson's 2. Mutex locks 3. Semaphore
Peterson’s Solution (Provable but not guaranteed on modern systems)
Two process solution!!
The processes alternate execution between their critical sections and remainder sections.
Assume that the load and store machine-language instructions are atomic; that is, cannot be interrupted (not the case on modern architectures)
Requires the two processes to share two variables:
->int turn;
->Boolean flag[2]
The variable turn indicates whose turn it is to enter the critical section
->If (turn == i), then Pi can enter its 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!
Synchronization Hardware (locking & atomic definitions)
Uniprocessors – could disable interrupts
- > Currently running code would execute without preemption
- > Generally too inefficient on multiprocessor systems
- –>Operating systems using this not broadly scalable
Locking: protecting critical regions via locks.
Atomic: non-interruptible
->Either test memory word and set value
->Or swap contents of two memory words
test_and_set instruction
Definition:
boolean test_and_set (boolean *target)
{
boolean rv = *target;
*target = TRUE;
return rv:
}
1. Executed atomically
2. Returns the original value of passed parameter
3. Set the new value of passed parameter to “TRUE”.
Solution using test_and_set()
Shared Boolean variable lock, initialized to FALSE Solution: do { while (test_and_set(&lock)) ; /* do nothing */ /* critical section */ lock = false; /* remainder section */ } while (true);
swap instruction
Definition: int swap(boolean *a, boolean *b) { boolean temp = *a; *a = *b; *b = temp; } 1. Executed atomically 2. Swaps the values of the two parameters ->Before: a=F, b=T ->End: a=T, b=F
Solution using compare_and_swap
mutual exclusion verified but not bounded-waiting. waiting for “luck”, swap function randomly executing
Shared boolean “lock” initialized to False; Local variable ”key” Solution: do { key = TRUE; while (key == TRUE) Swap(&lock, &key); /* critical section */ lock = FALSE; /* remainder section */ } while (true);
Bounded-waiting Mutual Exclusion with test_and_set (Good Solution!)
do { waiting[i] = true; key = true; while (waiting[i] && key) key = test_and_set(&lock); waiting[i] = false; /* critical section */ j = (i + 1) % n; (circular buffer) while ((j != i) && !waiting[j]) (search through each process) j = (j + 1) % n; if (j == i) lock = false; (Unlock for any process that comes after) else waiting[j] = false; /* remainder section */ } while (true);
Mutex Locks
Protect a critical section by first acquire() a lock then release() the lock
->Boolean variable indicating if lock is available or not
Calls to acquire() and release() must be atomic
->Usually implemented via hardware atomic instructions
But this solution requires busy waiting
->This lock therefore called a spinlock
NO CONTEXT SWITCH NEEDED, reduces overhead
acquire() and release() code
acquire() { while (!available) ; /* busy wait */ available = false;; } release() { available = true; } do { acquire lock critical section release lock remainder section } while (true);
Semaphore
Synchronization tool that provides more sophisticated ways (than Mutex locks) for process to synchronize their activities. Semaphore S – integer variable Can only be accessed via two indivisible (atomic) operations (wait & signal) ->wait() and signal() --->Originally called P() and V() Definition of the wait() operation wait(S) { while (S <= 0) ; // busy wait S--; } Definition of the signal() operation signal(S) { S++; }
Semaphore Usage
Counting semaphore – integer value can range over an unrestricted domain
Binary semaphore – integer value can range only between 0 and 1
->Same as a mutex lock
Can solve various synchronization problems
Consider P1 and P2 that require S1 to happen before S2
Create a semaphore “synch” initialized to 0
P1:
S1;
signal(synch);
P2:
wait(synch);
S2;