#include #define SIZE 10 using namespace std; class Queue { private: int jobs[SIZE]; int count, nextIn, nextOut; public: Queue( ) { count = nextIn = nextOut = 0; } void put( int job ) { while ( count == SIZE ); count++; jobs[nextIn] = job; nextIn = ( nextIn + 1 ) % SIZE; int get( ) { while ( count == 0 ); --count; int job = jobs[nextOut]; nextOut = ( nextOut + 1 ) % SIZE; return job; }; CSS503 Chapter 5: Synchronization 1 1"> #include #define SIZE 10 using namespace std; class Queue { private: int jobs[SIZE]; int count, nextIn, nextOut; public: Queue( ) { count = nextIn = nextOut = 0; } void put( int job ) { while ( count == SIZE ); count++; jobs[nextIn] = job; nextIn = ( nextIn + 1 ) % SIZE; int get( ) { while ( count == 0 ); --count; int job = jobs[nextOut]; nextOut = ( nextOut + 1 ) % SIZE; return job; }; CSS503 Chapter 5: Synchronization 1 1">

Presentation is loading. Please wait.

Presentation is loading. Please wait.

Chapter 5: Synchronization CSS503 Systems Programming

Similar presentations


Presentation on theme: "Chapter 5: Synchronization CSS503 Systems Programming"— Presentation transcript:

1 Chapter 5: Synchronization CSS503 Systems Programming
Prof. Munehiro Fukuda Computing & Software Systems University of Washington Bothell CSS503 Chapter 5: Synchronization

2 Revisiting Race Condition in Producer-Consumer Problem
Producer-Consumer Problem with two threads rather than two processes void* producer( void *args ) { cout << "producer thread: args = " << args << endl; Queue *queue = (Queue *)args; for ( int i = 0; ; i++ ) queue->put( i ); } void* consumer( void *args ) { cout << "consumer thread: args = " << args << endl; for ( int i = 0; ; i++ ) { int job = queue->get( ); cout << job << endl; if ( job != i ) { cout << "NAH!!!" << endl; exit( -1 ); int main( ) { Queue *queue = new Queue( ); pthread_t producer_t, consumer_t; pthread_create( &producer_t, NULL, producer, (void *)queue ); pthread_create( &consumer_t, NULL, consumer, (void *)queue ); pthread_join( producer_t, NULL ); pthread_join( consumer_t, NULL ); #include <pthread.h> #include <iostream> #define SIZE 10 using namespace std; class Queue { private: int jobs[SIZE]; int count, nextIn, nextOut; public: Queue( ) { count = nextIn = nextOut = 0; } void put( int job ) { while ( count == SIZE ); count++; jobs[nextIn] = job; nextIn = ( nextIn + 1 ) % SIZE; int get( ) { while ( count == 0 ); --count; int job = jobs[nextOut]; nextOut = ( nextOut + 1 ) % SIZE; return job; }; CSS503 Chapter 5: Synchronization 1 1

3 Chapter 5: Synchronization
Critical Section 3. Delta time exists When coming and entering CS Mutual Exclusion. If process Pi is executing in its critical section(CS), then no other processes can be executing in their critical sections. Progress. If no process is executing in its CS and there exist some processes that wish to enter their CS, then the selection of the processes that will enter the CS next cannot be postponed indefinitely. Bounded Waiting. A bound must exist on the number of times that other processes are allowed to enter their CS after a process has made a request to enter its CS and before that request is granted. When exiting from CS 2. Pick up a process to enter Critical Section 1. only one process CSS503 Chapter 5: Synchronization 2

4 Chapter 5: Synchronization
Solutions User level Peterson Language level Monitor OS level Semaphores Hardware Interrupt making, test & set, swap CSS503 Chapter 5: Synchronization 3 3

5 Naïve Algorithms User-Level Solution 1
Yielding by turn int turn = 0; // or 1 p0: p1: while ( turn != 0 ); while ( turn != 1 ); // critical section // ciritical section turn = 1; turn = 0; What if producer is p1? Declaring “I’m using” bool flag[0] = false; bool flag[1] = false; p0: p1: flag[0] = true; flag[1] = true; while ( flag[1] == true ); while ( flag[0] == true ); // critical section // critical section flag[0] = false; flag[1] = false; What if both p0 and p1 declared simultaneously? CSS503 Chapter 5: Synchronization 4 4

6 Dekker’s Algorithm User-Level Solution 2
Declaring “I’m using” as well as yielding by turn Available for two processes int turn = 0; // or 1 bool flag[0] = false; bool flag[1] = false; p0: p1: flag[0] = true; flag[1] = true; while ( flag[1] == true ) { while ( flag[0] == true ) { if ( turn != 0 ) { if ( turn != 1 ) { flag[0] = false; flag[1] = false; while ( turn != 0 ); while ( turn != 1 ); flag[0] = true; flag[1] = true; } } } } // critical section // ciritical section turn = 1; turn = 0; flag[0] = false; flag[1] = false; // Declare “I’m using” // if counterpart is using // if turn is mine, wait for s/he turns down the declaration // otherwise, wait till turn gets mine CSS503 Chapter 5: Synchronization 5 5

7 Test and Set, Swap Hardware-Level 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 CSS503 Chapter 5: Synchronization 6 6

8 Semaphores OS-Level Solution
Synchronization tool that does not require busy waiting Semaphore S – integer variable Two standard operations modify S: wait() and signal() Originally called P() and V() Mutual exculsion using semaphore Semaphore mutex; // initialized to 1 do { wait (mutex); // Critical Section signal (mutex); // remainder section } while (TRUE); Implementation of wait: wait(semaphore *S) { S->value--; if (S->value < 0) { add this process/thread to S->list; block(); } Implementation of signal: signal(semaphore *S) { S->value++; if (S->value <= 0) { remove a process/thread P from S->list; wakeup(P); CSS503 Chapter 5: Synchronization 7

9 Monitors Language-Level Solution
Entry queue p8 p7 p6 X: Y: p2 p4 p1 High-level language construct Only one process allowed in a monitor, thus executing its method A process in the monitor can wait on a condition variable, say x, thus relinquishing the monitor and allowing another process to enter A process can signal another process waiting on a condition variable (on x). A process signaling another process should exit from the monitor, because the signal process may have begun to work in the monitor. p3 p5 MethodA MethodB MethodC x.wait( ); x.signal( ) p1 CSS503 Chapter 5: Synchronization 8

10 Chapter 5: Synchronization
Pthread Monitors wait sets entry set main thread class Monitor { private: pthread_mutex_t lock; pthread_cond_t x; pthread_cond_t y; public: Monitor( ) { pthread_mutex_init( &lock, NULL ); pthread_cond_init( &x, NULL ); pthread_cond_init( &y, NULL ); } void methodA( ) { pthread_mutex_lock( &lock ); pthread_cond_wait( &x, &lock ); pthread_cond_signal( &y ); cout << "woke up from method A" << endl; pthread_mutex_unlock( &lock ); void methodB( ) { pthread_cond_wait( &y, &lock ); pthread_cond_signal( &x ); cout << "woke up from method B" << endl; void methodC( ) { cout << "signal to x on method A" << endl; } monitor; thread[1] thread[2] void *thread_func( void *arg ) { int id = *(int *)arg; if ( id == 1 ) monitor.methodA( ); // thread 1 waits in methodA else if ( id == 2 ) monitor.methodB( ); // thread 2 waits in methodB } int main( ) { pthread_t thread_id[2]; int logical_id[2] = {1, 2}; pthread_create( &thread_id[0], NULL, thread_func, (void *)&logical_id[0] ); pthread_create( &thread_id[1], NULL, thread_func, (void *)&logical_id[1] ); sleep( 1 ); monitor.methodC( ); // main thread wakes up thread 1 pthread_join( thread_id[0], NULL ); pthread_join( thread_id[1], NULL ); return 0; CSS503 Chapter 5: Synchronization 9

11 Chapter 5: Synchronization
Java Synchronization public class ClassA { // Every object has a lock associated with it. public synchronized void method1( ) { // Calling a synchronized method requires “owning” the lock. ….; // The lock is released when a thread exits the synchronized method. } public Synchronized void method2( ) { // If a calling thread does not own the lock it is placed in the entry set. private data a, b, c; CSS503 Chapter 5: Synchronization 10

12 Chapter 5: Synchronization
Java Monitor public void synchronized method1( ) { // Calling a synchronized method requires “owning” the lock. // If a calling thread does not own the lock it is placed in the entry set. while ( condition == false ) try { wait( ); // The thread releases a lock and places itself in the wait set. } catch( InterruptedException e ) { } } ….; notify( ); // The calling thread resumes one of threads waiting in the wait set. CSS503 Chapter 5: Synchronization 11

13 Classical Problem 3: Dining Philosophers Problem
THINKING HUNGRY EATING Shared data Semaphore chopStick[] = new Semaphore[5]; CSS503 Chapter 5: Synchronization 12

14 The Structure of Philosopher i
while ( true ) { // get left chopstick chopStick[i].P(); // get right chopstick chopStick[(i + 1) % 5].P(); // eat for awhile //return left chopstick chopStick[i].V( ); // return right chopstick chopStick[(i + 1) % 5].V( ); // think for awhile } Waiting Picked up A deadlock occurs! CSS503 Chapter 5: Synchronization 13

15 Dining-Philosophers Problem Using a Monitor
class DiningPhilosophers { private: pthread_mutex_t lock; enum State { THINKING, HUNGRY, EATING } state[MAX]; pthread_cond_t self[MAX]; void test( int i ) { // if phi-i's leftis not eating, phi-i is hungry, and // phi-i's right is not eating, then phi-i can eat! // Wake up phi-i if ( ( state[ ( i + MAX - 1 ) % MAX ] != EATING ) && ( state[i] == HUNGRY ) && ( state[ ( i + 1 ) % MAX ] != EATING ) ) { state[ i ] = EATING; pthread_cond_signal( &self[ i ] ); } public: DiningPhilosophers( ) { pthread_mutex_init( &lock, NULL ); for ( int i = 0; i < MAX; i++ ) { pthread_cond_init( &self[i], NULL ); state[i] = THINKING; void pickUp( int i ) { pthread_mutex_lock( &lock ); state[ i ] = HUNGRY; // I got hungry test( i ); // Can I have my left and right chopsticks? if ( state[ i ] != EATING ) // No, I can't, then I should wait pthread_cond_wait( &self[ i ], &lock ); cout << "philosopher[" << i << "] picked up chopsticks."<< endl; pthread_mutex_unlock( &lock ); } void putDown( int i ) { cout << "philosopher[" << i << "] put down chopsticks."<< endl; state[ i ] = THINKING; // I'm stuffed and now thinking. // test left and right neighbors test( ( i + MAX - 1 ) % MAX ); // if possible, wake up my left. test( ( i + 1 ) % MAX ); // if possible, wake up my right. CSS503 Chapter 5: Synchronization 14

16 Programming Assignment 2 Sleeping Barber Problems
The original problem Call in a new customer Take a nap if no customers Give a haircut service Have a waiting seat Wake up a barber Leave the shop if full Our extended problem: multiple barbers CSS503 Chapter 5: Synchronization 15

17 Programming Assignment 2 Sleeping Barber Problems
Shop as a Monitor #ifndef _SHOP_H_ #define _SHOP_H_ #include <pthread.h> // the header file for the pthread library #include <queue> // the STL library: queue using namespace std; #define DEFAULT_CHAIRS 3 // the default number of chairs for waiting = 3 #define DEFAULT_BARBERS 1 // the default number of barbers = 1 class Shop { public: Shop( int nBarbers, int nChairs ); // initialize w/ nBarbers and nChairs Shop( ); // initialize w/ 1 barber and 3 chairs int visitShop( int id ); // non-negative number only when serviced void leaveShop( int customerId, int barberId ); void helloCustomer( int id ); void byeCustomer( int id ); int nDropsOff; // the number of customers dropped off }; #endif if ((barber = shop.visitShop(id)) != -1) shop.leaveShop(id, barber); while(true) { shop.helloCustomer( id ); // take some service time usleep( serviceTime ); shop.byeCustomer( id ); } CSS503 Chapter 5: Synchronization 16

18 Programming Assignment 2 Sleeping Barber Problems
int visitShop( int id ) Enter the critical section. If all chairs are full { Print “id leaves the shop because of no available waiting chairs”. Increment nDropsOff. Leave the critical section. Return –1. } if all barbers are busy { Take a waiting char (or Push the customer in a waiting queue). Print “id takes a waiting chair. # waiting seats available = …”. Wait for a barber to wake me up. Pop me out from the queue. Get my barber whose id is barberId. Print “id moves to a service chair[barberId], # waiting seats available = …”. Have barberId start my haircut, (i.e., wake him up). Return barberId. void leaveShop( int customerId, int barberId ) Print “customerId wait for barber[barberId] to be done with hair-cut.” While barberId is cutting my hair, Wait. Print “customerId says good-by to barber[]”. void helloCustomer( int id ) Enter the critical section. If I have no customer and all the waiting chairs are empty { Print “ –id sleeps because of no customers.” wait until a customer wakes me up. } Print “–id starts a hair-cut service for customer[id].” Leave the critical section. byeCustomer( int id ) Print “–id says he's done with a hair-cut service for customer[id].” Wakes up my customer. Print ““–id calls in another customer.” Wakes up another customer who is waiting on a waiting chair. CSS503 Chapter 5: Synchronization 17

19 Chapter 5: Synchronization
Discussion 1 Why does the latest Java compiler deprecate the use of resume, suspend, and stop? Consider an undesired situation incurred when those three functions are used. Solve Textbook Exercises: 5.4, 5.10, 5.11, and 5.15 CSS503 Chapter 5: Synchronization 18

20 Chapter 5: Synchronization
Discussions 2 Consider the following five options to implement synchronization between producer and a consumer, both accessing the same bounded buffer. When we run a producer and a consumer on shared-memory-based dual-processor computer, which of the following implementation is the fastest? Justify your selection. Also select the slowest implementation and justify your selection. User the many-to-one thread mapping model, allocate a user thread to a producer and a consumer respectively, and let them synchronize with each other using test-and-set instructions. Use the many-to-one thread mapping model, allocate a user thread to a producer and a consumer respectively, and let them synchronize with each other using semaphore. User the one-to-one thread mapping model, allocate a user thread, (i.e., a kernel thread) to a producer and a consumer respectively, and let them synchronize with each other using test-and-set instructions. User the one-to-one thread mapping model, allocate a user thread, ( i.e., a kernel thread) to a producer and a consumer respectively, and let them synchronize with each other using semaphores. Allocate a different process to a producer and a consumer respectively, and let them synchronize with each other using semaphores. (Note that a bounded buffer is mapped onto the shared memory allocate by those processes through shmget and shmat.) CSS503 Chapter 5: Synchronization 19


Download ppt "Chapter 5: Synchronization CSS503 Systems Programming"

Similar presentations


Ads by Google