Concurrency in Shared Memory Systems: Synchronization and Mutual Exclusion
Concurrency in Shared Memory Systems: Synchronization and Mutual Exclusion
Concurrency in Shared Memory Systems: Synchronization and Mutual Exclusion
Concurrent Execution
On a uniprocessor, concurrency occurs when the CPU is switched from one process to another, so the instructions of several threads are interleaved (alternate) On a multiprocessor, execution of instructions in concurrent threads may be overlapped (occur at same time) if the threads are running on separate processors.
Concurrent Execution
An interrupt, followed by a context switch, can take place between any two instructions. Hence the pattern of instruction overlapping and interleaving is unpredictable. Processes and threads execute asynchronously we cannot predict if event a in process i will occur before event b in process j.
Example
Let balance = 100, withdrawal1=50, and withdrawal2 = 75. Threadi will execute the following algorithm:
if (balance >= withdrawali) balance = balance withdrawali else // print Cant overdraw account!
If thread1 executes first, balance will be 50 and thread2 cant withdraw funds. If thread2 executes first, balance will be 25 and thread1 cant withdraw funds.
But --- what if the two threads execute concurrently instead of sequentially? Break down into machine-level operations:
if (balance >= withdrawali) balance = balance withdrawali move balance to a register compare register to withdrawali branch if less-than register = register withdrawali store register contents in balance
Example-Multiprocessor
(A possible instruction sequence showing interleaved execution)
Thread 1 (2) Move balance to register1 (register = 100) (4) compare register1 to withdraw1 (5)register1 = register1 withdraw1 (100-50) (7) store register1 in balance (balance = 50)
Thread 2 (1) Move balance to register2 (register = 100) (3) compare register2 to withdraw2 (6) register2 = register2 withdraw2 (100 75) (8) store register2 in balance (balance = 25)
Example Uniprocessor
(A possible instruction sequence showing interleaved execution)
Thread 2
P1s time slice expires its state is saved P1 is re-scheduled; its state is restored (Reg. = 100)
Move balance to reg. balance >= withdraw2 balance = balance withdraw2 = (100-75)
Race Conditions
The previous examples illustrate a race condition (data race): an undesirable condition that exists when several processes access shared data, and
At least one access is a write and The accesses are not mutually exclusive
Mutual Exclusion
Mutual exclusion forces serial resource access as opposed to concurrent access. When one thread locks a critical resource, no other thread can access it until the lock is released. Critical section (CS): code that accesses shared resources. Mutual exclusion guarantees that only one process/thread at a time can execute its critical section, with respect to a given resource.
Solution Model
Begin_mutual_exclusion /* some mutex primitive execute critical section End_mutual_exclusion /* some mutex primitive The problem: How to implement the mutex primitives?
Busy wait solutions (e.g., test-set operation, spinlocks of various sorts, Petersons algorithm) Semaphores (OS feature usually, blocks waiting process) Monitors (language feature e.g. Java)
Semaphores
Definition: an integer variable on which processes can perform two indivisible operations, P( ) and V( ), + initialization. (P and V sometimes called Wait & Signal) Each semaphore has a wait queue associated with it. Semaphores are protected by the operating system.
Semaphores
Binary semaphore: only values are 1 and 0 Traditional semaphore: may be initialized to any non-negative value; can count down to zero. Counting semaphores: P & V operations may reduce semaphore values below 0, in which case the negative value records the number of blocked processes. (See CS 490 textbook)
Semaphores
Are used to synchronize and coordinate processes and/or threads Calling the P (wait) operation may cause a process to block Calling the V (signal) operation never causes a process to block, but may wake a process that has been blocked by a previous P operation.
Traditional Semaphore
P(S): if S > = 1 then S = S 1 else block the process on S queue
Counting Semaphore
P(S): S=S1 if ( S < 0) then block the process on S queue
V(S): if some processes are blocked on S queue then unblock a process else S = S + 1
V(S): S=S+1 if (S <= 0) then move a process from S queue to the Ready queue
V(S)
Example Uniprocessor
Thread 1 P(S) S is decremented: S = 0,
T1 continues to execute
Thread 2
T1s time slice expires its state is saved T1 is re-scheduled; its state is restored (Reg. = 100)
P(S)
Since S = 0, T2 is blocked
Since !(50>=75), T2 does not make withdrawal Since no thread is waiting, S is set back to 1
if S >= 1 then S = S 1 else block the process on S queue execute critical section if processes are blocked on the queue for S then unblock a process else S = S + 1
Suppose a process P2 wants to wait on an event of some sort (call it A) which is to be executed by another process P1 Initialize a shared semaphore to 0 By executing a wait (P) on the semaphore, P2 will wait until P1 executes event A and signals, using the V operation.
Dining Philosophers: resource deadlock Producer-consumer: buffering (as of messages, input data, etc.) Readers-writers: data base or file sharing
Readers priority Writers priority
Producer-Consumer
Producer processes and consumer processes share a (usually finite) pool of buffers. Producers add data to pool Consumers remove data, in FIFO order
Producer-Consumer Requirements
The processes are asynchronous. A solution must ensure producers dont deposit data if pool is full and consumers dont take data if pool is empty. Access to buffer pool must be mutually exclusive since multiple consumers (or producers) may try to access the pool simultaneously.
Restrictions:
Multiple readers may read concurrently, but when a writer is writing, there should be no other writers or readers.
Compare to Prod/Cons
Differences between Readers/Writers (R/W) and Producer/Consumer (P/C):
Data in P/C is ordered - placed into buffer and retrieved according to FIFO discipline. All data is read exactly once. In R/W, same data may be read many times by many readers, or data may be written by writer and changed before any reader reads. No order enforced on reads.
// Initialization code integer readcount = 0; // done only once semaphore x, wsem = 1; // done only once
procedure reader; begin repeat P (x); readcount = readcount + 1; if readcount = =1 then P (wsem); V (x); read data; P (x); readcount = readcount - 1; if readcount == 0 then V(wsem); V (x); forever end;
Any Questions?
Can you think of any real examples of producerconsumer or reader-writer situations?
Use a variable as a semaphore; access via P & V functions. A thread executes P(S) and finds S = 0. Then it yields control.