Presentation is loading. Please wait.

Presentation is loading. Please wait.

Synchronization.

Similar presentations


Presentation on theme: "Synchronization."— Presentation transcript:

1 Synchronization

2 Process Synchronization
Classic Problems of Synchronization Synchronization Examples Background The Critical-Section Problem Peterson’s Solution Synchronization Hardware Mutex Semaphores Monitors Other ways ways to provide synchronization Process Serializabillity Atomic Transactions

3 Objectives To introduce the critical-section problem, whose solutions can be used to ensure the consistency of shared data To present both software and hardware solutions of the critical- section problem

4 Concurrency Concurrent access to shared data may result in data inconsistency Maintaining data consistency requires mechanisms to ensure the orderly execution of cooperating processes

5 Concurrency …. Concurrent threads/processes (informal) Asynchronous
Two processes are concurrent if they run at the same execution is interleaved in any order Asynchronous The processes require occasional synchronization Independent They do not have any reliance on each other Synchronous Frequent synchronization with each other – order of execution is guaranteed Parallel Processes run at the same time on separate processors

6 Race Conditions A race condition is a bug: Example Withdrawal Deposit
– The outcome of concurrent threads are unexpectedly dependent on a specific sequence of events. Example Your current bank balance is $1,000. Withdraw $500 from an ATM machine while a $5,000 direct deposit is coming in Execute concurrently Withdrawal Deposit Read account balance Subtract 500 Write account balance Read account balance Add 500 Write account balance Possible outcomes: Total balance = $5500, $500 $6000, Krzyzanowski

7 Race Condition count++ could be implemented as register1 = count register1 = register count = register1 count-- could be implemented as register2 = count register2 = register count = register2 Consider this execution interleaving with “count = 5” initially: S0: producer execute register1 = count {register1 = 5} S1: producer execute register1 = register {register1 = 6} S2: consumer execute register2 = count {register2 = 5} S3: consumer execute register2 = register {register2 = 4} S4: producer execute count = register1 {count = 6 } S5: consumer execute count = register2 {count = 4}

8 _} Synchronization Synchronization deals with race conditions
' Synchronization Synchronization deals with race conditions developing techniques to avoid Something as simple x = x + 1; as Compiles to movl addl this and may cause a race _x (%rip), %eax condition: _} Potential points of preemption for a race condition $1, %eax .._'. %eax, _x (%rip) February 14, 2015 © Paul Krzyzanowski 4

9 Critical Section The section of code that accesses a shared resource and whose execution should be atomic. Execution should not be interrupted during a critical sectopm

10 l l Avoid Race Conditions • Read account balance • Add 5000
' Avoid Race Conditions • Grab and release locks around critical sections • Wait if you cannot get a lock Execute concurrently Withdrawal Deposit Enter Critical Section l Enter Critical Section Acquire(transfer_lock) Acquire(transfer_lock) J J \ • Read account balance • Subtract 500 • Write account balance I • Read account balance • Add 5000 • Write account balance ' Critical Section I Critical Section Subtract 500 Write account I I balance I ' Exit Critical Section J Release(transfer_lock) Release(transfer_lock) l Exit Critical Section \ J February 14, 2015 © Paul Krzyzanowski 6

11 The Critical Section Problem
Design a protocol to allow threads to enter a critical section February 14, 2015 © Paul Krzyzanowski 7

12 Solution to Critical-Section Problem Requirements
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

13 Solution #1: Disable Interrupts
Disable all system interrupts before entering a section and re-enable them when leaving Bad! critical Gives the thread too much control over the system Stops time updates and scheduling What if the logic in the critical section goes wrong? What if the critical section has a dependency on some interrupt, thread, or system call? other What about multiple processors? Disabling interrupts one processor affects just Advantage – Simple, guaranteed to work – Was often used in the uniprocessor kernels February 14, 2015 © Paul Krzyzanowski 10

14 We Want Mutual Exclusion Around Critical Regions
Tanenbaum & Bo,Modern Operating Systems:4th ed., (c) 2013 Prentice-Hall, Inc. All rights reserved.

15 Mutual Exclusion with Busy Waiting
While (not my turn); Critical section; Indicate my turn is over Busy wait

16 Peterson’s Solution Two process solution
Assume that the LOAD and STORE instructions are atomic; that is, cannot be interrupted. Peterson’s solution requires that 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!

17 Algorithm for Process Pi
do { flag[i] = TRUE; turn = j; while (flag[j] && turn == j); critical section flag[i] = FALSE; remainder section } while (TRUE); Use Pj to denote the other process. So P0 and P1 , then If I’m 0, j=1 If I’m 1, j = 0

18 Peterson’s Disadvantages
Difficult to implement for an arbitrary number of threads BUSY WAITING Busy waiting → Consumes processors time Starvation is possible → Selection of waiting process is arbitrary Deadlock is possible → The flag owned by reset by low priority process can be preempted by high priority process before lock is released

19 Synchronization Hardware Solution
Many systems provide hardware support for 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 Modern machines provide special atomic hardware instructions Atomic = non-interruptable Either test memory word and set value Or swap contents of two memory words

20 Solution to Critical-section Problem Using Locks
do { acquire lock critical section release lock remainder section } while (TRUE);

21 TestAndndSet Instruction
Definition: boolean TestAndSet (boolean *target) { boolean rv = *target; *target = TRUE; return rv: } OR: boolean TestAndSet (boolean *target) { if (*target==TRUE) {return TRUE; } else { *target = True return FALSE; } } Kent State example

22 Solution to Critical-Section using TestAndSet
Shared boolean variable lock., initialized to false. Solution: bool lock = false; do { while ( TestAndSet (&lock )) ; // do nothing // critical section lock = FALSE; // remainder section } while (TRUE);

23 Implementing TestAndSet with Function
void thread_lock( bool mylock) {while (test_and_set(mylock)==true) ; // spinlock void thread_unlock(bool myLock) {myLock = false; } int main () { bool myCriticalSectionLock; thread_lock (myCriticalSectionLock); // critical section thread_unlock (myCriticalSectionLock); return 0; }

24 Mutex Lock - Mutual Exclusion
A shared variable that can be on one of 2 states: Locked Unlocked A thread (or process) needs access to a critical region lock with Mutex_lock If the lock is available, the thread gets the lock and enters critical section If not, the thread is blocked until the mutex is unlocked. If there are multible threads waiting the next one unlocked is chose at random

25 NOT BUSY WAITING Thread is moved to a wait state until it is released.

26 MUTEX : Mutual Exclusion Locks
Values of the lock are either 0 or 1 Can be used between threads in the same process …. only #include <pthread.h> int pthread_mutex_init(); int pthread_mutex_lock(pthread_mutex_t *mutex); …. int pthread_mutex_unlock(pthread_mutex_t *mutex); int pthread_mutex_trylock(pthread_mutex_t *mutex);

27 Using mutexes #include <pthread.h> pthread_mutex_t myMutexLock; pthread_mutex_init( &myMutexLock, NULL); //Non critical stuff pthread_mutex_lock(&myMutexLock); // critical section pthread_mutex_unlock(&myMutexLock);

28 Semaphore Originally called P() and V() wait (S) { while S <= 0
Semaphore S – integer variable Two standard operations modify S: wait() and signal() Originally called P() and V() Less complicated Can only be accessed via two indivisible (atomic) operations wait (S) { while S <= 0 ; // no-op S--; } signal (S) { S++;

29 Semaphores down(sem s) { //initialize if (s > 0) mutex = 1; s = s
• Count # of wake-ups saved • Two atomic operations: for future use down(sem s) { //initialize if (s > 0) mutex = 1; s else = s 1; down(&mutex) sleep on event s } up(sem s) { if (someone wake up else // critical section is waiting on s) up(&mutex) one of the threads Binary semaphore s = s + 1; } February 14, 2015 © Paul Krzyzanowski 26

30 Semaphores Count the number of threads that may enter a critical
section at any given time. Each down decreases the number of future accesses When no more are allowed, processes have to wait Each up lets a waiting process get in February 14, 2015 © Paul Krzyzanowski 27

31 Semaphore as General Synchronization Tool
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 Also known as mutex locks Can implement a counting semaphore S as a binary semaphore Provides mutual exclusion Semaphore mutex; // initialized to 1 do { wait (mutex); // Critical Section signal (mutex); // remainder section } while (TRUE);

32 Semaphore Implementation
Must guarantee that no two processes can execute wait () and signal () or post() on the same semaphore at the same time Thus, implementation becomes the critical section problem where the wait and signal code are placed in the critical section. Could now have busy waiting in critical section implementation But implementation code is short Little busy waiting if critical section rarely occupied Note that applications may spend lots of time in critical sections and therefore this is not a good solution.

33 POSIX Semaphore Example
#include <semaphore.h> sem_t sem_name; // defines a semaphore object /* int sem_init(sem_t *sem, int pshared, unsigned int value); sem points to a semaphore object to initialize pshared is a flag indicating whether or not the semaphore should be shared with fork()ed processes.LinuxThreads does not currently support shared semaphores value is an initial value to set the semaphore to */ sem_init(&sem_name, 0, 10);

34 POSIX Semaphore Example (cont)
/* To wait on a semaphore, use sem_wait: int sem_wait(sem_t *sem): If the value of the semaphore is negative, the calling process blocks; one of the blocked processes wakes up when another process calls sem_post. */ sem_wait(&sem_name); /* To increment the value of a semaphore, use sem_post: int sem_post(sem_t *sem); Example of use: It increments the value of the semaphore and wakes up a blocked process waiting on the semaphore, if any */ sem_post(&sem_name);

35 POSIX Semaphore Example (cont)
/* To find out the value of a semaphore, use int sem_getvalue(sem_t *sem, int *valp); This gets the current value of sem and places it in the location pointed to by valp . */ int value; sem_getvalue(&sem_name, &value); /* To destroy a semaphore, use int sem_destroy(sem_t *sem); This destroys the semaphore; no threads should be waiting on the semaphore if its destruction is to succeed. sem_destroy(&sem_name);

36 Classical Problems of Synchronization
Bounded-Buffer Problem Readers and Writers Problem Dining-Philosophers Problem

37 Producer int count = 0; while (true) { /* produce an item and put in nextProduced */ while (count == BUFFER_SIZE) ; // do nothing buffer [in] = nextProduced; in = (in + 1) % BUFFER_SIZE; count++; } At most the buffer can fit BUFFER_SIZE-1 items count is initialized to 0 and incremented each time we add an item to the buffer count is shared between producer and consumer

38 Consumer while (count == 0) ; // do nothing
while (true) { while (count == 0) ; // do nothing nextConsumed = buffer[out]; out = (out + 1) % BUFFER_SIZE; count--; /* consume the item in nextConsumed } count is decremented each time we remove an item to the buffer count is shared between producer and consumer Can we trust this?

39 Bounded-Buffer Problem
N buffers, each can hold one item Semaphore mutex initialized to the value 1 Semaphore full initialized to the value 0 Semaphore empty initialized to the value N.

40 Bounded Buffer Problem (Cont.)
The structure of the producer process do { // produce an item in nextp wait (empty); wait (mutex); // add the item to the buffer signal (mutex); signal (full); } while (TRUE);

41 Bounded Buffer Problem (Cont.)
The structure of the consumer process do { wait (full); wait (mutex); // remove an item from buffer to nextc signal (mutex); signal (empty); // consume the item in nextc } while (TRUE);

42 Readers-Writers Problem
A data set is shared among a number of concurrent processes Readers – only read the data set; they do not perform any updates Writers – can both read and write Problem – allow multiple readers to read at the same time. Only one single writer can access the shared data at the same time Shared Data Data set Semaphore mutex initialized to 1 Semaphore wrt initialized to 1 Integer readcount initialized to 0

43 Readers-Writers Problem (Cont.)
The structure of a writer process do { wait (wrt) ; // writing is performed signal (wrt) ; } while (TRUE);

44 Readers-Writers Problem (Cont.)
The structure of a reader process do { wait (mutex) ; readcount ++ ; if (readcount == 1) wait (wrt) ; signal (mutex) // reading is performed readcount - - ; if (readcount == 0) signal (wrt) ; signal (mutex) ; } while (TRUE);

45 Problems with Semaphores
Incorrect use of semaphore operations: signal (mutex) …. wait (mutex) wait (mutex) … wait (mutex) Omitting of wait (mutex) or signal (mutex) (or both)

46 Deadlock and Starvation
Deadlock – two or more processes are waiting indefinitely for an event that can be caused by only one of the waiting processes Let S and Q be two semaphores initialized to 1 P P1 wait (S); wait (Q); wait (Q); wait (S); . . signal (S); signal (Q); signal (Q); signal (S); Starvation – indefinite blocking. A process may never be removed from the semaphore queue in which it is suspended Priority Inversion - Scheduling problem when lower-priority process holds a lock needed by higher-priority process

47 Dining-Philosophers Problem
Shared data Bowl of rice (data set) Semaphore chopstick [5] initialized to 1

48 Dining-Philosophers Problem (Cont.)
The structure of Philosopher i: do { wait ( chopstick[i] ); wait ( chopStick[ (i + 1) % 5] ); // eat signal ( chopstick[i] ); signal (chopstick[ (i + 1) % 5] ); // think } while (TRUE);

49 Condition variables Remember:
A mutex prevents multiple threads from accessing a shared variable at the same time Condition variable: allows one thread to inform other threads about changes in the state of a shared variable (or research) and allows other threads to wait (block/sleep) for such notification While mutexes implement synchronization by controlling thread access to data, condition variables allow threads to synchronize based upon the actual value of data.

50 Signaling Changes of State: Condition Variables
Condition variables allows one thread to inform other threads about changes in state of a shared variable or resource and the other threads to wait(block) for such notification ….. instead of continually checking

51 Monitor Language supplied construct
A monitor class presents a set of programmer defined operations which can provide mutual exclusion within the monitor. Procedures Monitor Properties Shared data can only be accessed by monitor’s procedures Only ONE process at a time can execute the monitor

52 Schematic view of a Monitor

53 Monitor with Condition Variables

54 Solution to Dining Philosophers
monitor DP { enum { THINKING; HUNGRY, EATING) state [5] ; condition self [5]; void pickup (int i) { state[i] = HUNGRY; test(i); if (state[i] != EATING) self [i].wait; } void putdown (int i) { state[i] = THINKING; // test left and right neighbors test((i + 4) % 5); test((i + 1) % 5);

55 Solution to Dining Philosophers (cont)
void test (int i) { if ( (state[(i + 4) % 5] != EATING) && (state[i] == HUNGRY) && (state[(i + 1) % 5] != EATING) ) { state[i] = EATING ; self[i].signal () ; } initialization_code() { for (int i = 0; i < 5; i++) state[i] = THINKING;

56 Solution to Dining Philosophers (cont)
Each philosopher I invokes the operations pickup() and putdown() in the following sequence: DiningPhilosophters.pickup (i); EAT DiningPhilosophers.putdown (i);

57 CONDITION VARIABLES USING PTHREADS
The principle operations are signal and wait Two operations on a condition variable: pthread_cond_wait() – a process that invokes the operation is suspended. pthread_cond_signal()– resumes one of processes (if any) that invoked pthread_cond_wait()

58 Implementing Condition Variables
#include <pthread.h> pthead_cond_t condVar = PTHREAD_COND INITIALIZER; int pthread_cond_signal(pthead_cond_t * condVar ); int pthread_cond_broadcast (pthead_cond_t * condVar ); int pthread_cond_wait(pthead_cond_t * condVar, pthread_mutex_t *mutex );


Download ppt "Synchronization."

Similar presentations


Ads by Google