440 likes | 538 Views
CS 241 Lecture 15 9/29/2006. Synchronization Programming. Yuanyuan Zhou. Chapters: R &R 550-564, Stallings Chapter A.3. Lecture Quiz. Answer bubbles must be carefully shaded in pencil. Put your Last name, Network ID, and student number (UID from student card) in bubble sheet.
E N D
CS 241 Lecture 15 9/29/2006 Synchronization Programming Yuanyuan Zhou Chapters: R &R 550-564, Stallings Chapter A.3
Lecture Quiz • Answer bubbles must be carefully shaded in pencil. • Put your Last name, Network ID, and student number (UID from student card) in bubble sheet. • Turn sheet over and answer each question for the given question numbers • Make sure you submit to the TA
Administrative • This week • MP quiz quizmp3 in Discussion Sections or office hours • SMP4 due Sunday at 10:00pm. • Self Assessment Quiz Wk 6
Content of This Lecture Goals: Having you familiar and comfortable with synchronization programming How? Classic synchronization problems Producer-consumer problem Reader-writer problem Dinning philosopher problem Barber problem Common mistakes
Producer-Consumer Problem • Problem description • A producer: in an infinite loop and produce one item each iteration into the buffer • A consumer: in an infinite loop and consumes one item each iteration from the buffer • Buffer size: can only hold at most N items • Real world example • Web server • Producer: dispatcher threads • Consumer: worker threads
Need 4 volunteers • 1 Consumer • Consume donuts following the program (using step papers) • Each time only one step • 1 Producer • Produce donuts following theprogram ((using step papers) • Each time only one step • 2 Schedulers • Cannot run a process forever • Switch from one to another after 1 or many steps • Try to create some error/deadlock ASAP • Minimize #donuts consumed • Then can eat some donut
Producer-Consumer Program int counter; //initialize to 0 // Producer repeat • read the counter value loud; • if(Counter < 4) { // say it loudly • increment the counter loud; • update the counter with the incremented value; • put a donut onto a plate; //ERROR if no more empty plate}else{ • yield to the scheduler for this turn;} Until YY says stop // consumer repeat • read the counter value loud; • if(Counter > 0) { // say it loudly • decrement counter loud; • update the counter with the incremented value; • consume the donut from a plate; //ERROR if no more donut}else{ • yield to the scheduler for this turn;} Until YY says stop
Producer-Consumer Program int counter; //initialize to 0 Mutex m; // Producer repeat • Mutex_Lock(&m); • read counter value on the board loud; • if(Counter < 4) { // say it loudly • increment the counter loud; • update the counter with the incremented value; • put a donut onto a plate; //ERROR if no more empty plate • Mutex_Unlock(&m)}else{ • yield to the scheduler for this turn;} Until YY says stop // consumer repeat • Mutex_Lock(&m); • read counter value on the board loud; • if(Counter > 0) { // say it loudly • decrement counter loud; • update the counter with the incremented value; • consume the donut from a plate; //ERROR if no more donutMutex_Unlock(&m)}else{ • yield to the scheduler for this turn;} Until YY says stop
Audience: How to fix it? (also donut) int counter; //initialize to 0 Mutex m; // Producer repeat • Mutex_Lock(&m); • read counter value on the board loud; • if(Counter < 4) { // say it loudly • increment the counter loud; • update the counter with the incremented value; • put a donut onto a plate; //ERROR if no more empty plate • Mutex_Unlock(&m);}else{ • yield to the scheduler for this turn;} Until YY says stop // consumer repeat • Mutex_Lock(&m); • read counter value on the board loud; • if(Counter > 0) { // say it loudly • decrement counter loud; • update the counter with the incremented value; • consume the donut from a plate; //ERROR if no more donut • Mutex_Unlock(&m);}else{ • yield to the scheduler for this turn;} Until YY says stop
Correct Implementation: Last Demo int counter; //initialize to 0 Mutex m; // Producer repeat • Mutex_Lock(&m); • read counter value on the board loud; • if(Counter < 4) { // say it loudly • increment the counter loud; • update the counter with the incremented value; • put a donut onto a plate; //ERROR if no more empty plate • Mutex_Unlock(&m);}else{ • Mutex_Unlock(&m); • yield to the scheduler for this turn;} Until YY says stop // consumer repeat • Mutex_Lock(&m); • read counter value on the board loud; • if(Counter > 0) { // say it loudly • decrement counter loud; • update the counter with the incremented value; • consume the donut from a plate; //ERROR if no more donut • Mutex_Unlock(&m);}else{ • Mutex_Unlock(&m); • yield to the scheduler for this turn;} Until YY says stop
Another Solution using Semaphores Semaphore Full; //initialize to 0 Semaphore Empty; //initialize to 4 Mutex m; // Producer repeat • P(&empty) • Mutex_lock(&m); • put a donut onto a plate; • Mutex_Unlock(&m); • V(&full); Until YY says stop // consumer repeat • P(&full) • Mutex_lock(&m); • get a donut from a plate; • Mutex_Unlock(&m); • V(&empty); Until YY says stop
First Reader-Writer Problem • readers: read data • writers: write data • Rule: • Multiple readers can read the data simultaneously • Only one writer can write the data at any time • A reader and a writer cannot in critical section together. • Locking table: whether any two can be in the critical section simultaneously
First Reader-Writer Solution • Does it work? What if? • Problem with this solution Mutex m, wrt; int readcount; // shared and initialized to 0 // Writer // Reader Lock(&m); readcount:=readcount+1; Lock(&wrt); if (readcount == 1) lock(&wrt); ...... unlock(&m); writing performed .... ..... reading performed lock(&m); Lock(&wrt); readcount:=readcount-1; if (readcount == 0) unlock(&wrt); Unlock(&m);
Dining Philosophers: an intellectual game • Philosophers eat/think • Eating needs 2 forks • Pick one fork at a time
Need 5 volunteers • 3 Philosophers • Follow the program to • Think • Eat a donut with 2 forks • 2 Schedulers • Cannot run a process forever • Can switch from one to another after 1 or many steps • Try to create some error/deadlock ASAP • Minimize #donuts consumed • Then can eat some donut
Demo 1 Philosopher() { repeat • think; //say something intelligent • take left hand fork; • take right hand fork; • eat one bite; • put left hand fork; • put right hand fork; Until YY says stop; }
Demo 2: Will it work? Mutex m; Philosopher() { repeat • think; //say something intelligent • Mutex_Lock(&m); • take left hand fork; • take right hand fork; • Mutex_Unlock(&m); • eat one bite;Mutex_Lock(&m); • put left hand fork; • put right hand fork; • Mutex_Unlock(&m); Until YY says stop; }
Dining Philosophers Solution Please give an implementation of take_forks() and put_forks();
The Sleeping Barber Problem • N customer Chairs • One barber can cut one customer’s hair at any time • No customer, goes to sleep
The Sleeping Barber Solution (1) Please give an implementation of Barber() and Customer();
The Sleeping Barber Solution (3) Solution to sleeping barber problem.
Be Careful When Using Semaphores // Violation of Mutual Exclusion Up(mutex); mutexUnlock(); critical section criticalSection(); Down(mutex); mutexLock(); // Deadlock Situation Down(mutex); mutexLock(); critical section criticalSection(); Down(mutex); mutexLock(P); // Violation of Mutual Exclusion (omit wait(mutex)/mutexLock()) critical section critical Section(); Up(mutex); mutexUnlock(); // Deadlock Situation (omit signal(mutex)/mutexUnlock()) Down(mutex); mutexLock(); critical section criticalSection();
Summary Classic synchronization problems Producer-consumer Read-writer Dinning philosopher Sleeping barber
bufin bufout Producer Consumer Problem #include <pthread.h> #include "buffer.h" static buffer_t buffer[BUFSIZE]; static pthread_mutex_t bufferlock = PTHREAD_MUTEX_INITIALIZER; static int bufin = 0; static int bufout = 0;
Producer Consumer Problem int getitem(buffer_t *itemp) { /* remove item from buffer and put in *itemp */ int error; if (error = pthread_mutex_lock(&bufferlock)) /*no mutex, give up*/ return error; *itemp = buffer[bufout]; bufout = (bufout + 1) % BUFSIZE; return pthread_mutex_unlock(&bufferlock); } int putitem(buffer_t item) { /* insert item in the buffer */ int error; if (error = pthread_mutex_lock(&bufferlock)) /*no mutex, give up*/ return error; buffer[bufin] = item; bufin = (bufin + 1) % BUFSIZE; return pthread_mutex_unlock(&bufferlock); }
bufin bufout Producer Consumer using Semaphores #include <errno.h> #include <pthread.h> #include <semaphore.h> #include "buffer.h" static buffer_t buffer[BUFSIZE]; static int bufin = 0; static int bufout = 0; static sem_t mutexbuffer; static sem_t semitems; static sem_t semslots; Note: #semitems+#semslots=BUFSIZE
Producer Consumer Semaphores int bufferinit(void) { /*call this exactly once BEFORE getitem and putitem */ int error; if (sem_init(&semitems, 0, 0)) return errno; if (sem_init(&semslots, 0, BUFSIZE)) { error = errno; sem_destroy(&semitems); /* free the other semaphore */ return error; } if (sem_init(&mutexbuffer, 0, 1)) { error = errno; sem_destroy(&semitems); sem_destroy(&semitems); return error; } return 0; }
Producer Consumer Semaphores int getitem(buffer_t *itemp) { /* remove item from buffer and put in *itemp */ int error; while (((error = sem_wait(&semitems)) == -1) && (errno == EINTR)) ; if (error) return errno; if (error = sem_wait(&mutexbuffer)) return error; *itemp = buffer[bufout]; bufout = (bufout + 1) % BUFSIZE; if (error = sem_post(&mutexbuffer)) return error; if (sem_post(&semslots) == -1) return errno; return 0; }
Producer Consumer Semaphores int putitem(buffer_t item) { /* insert item in the buffer */ int error; while (((error = sem_wait(&semslots)) == -1) && (errno == EINTR)) ; if (error) return errno; if (error = sem_wait(&mutexbuffer)) return error; buffer[bufin] = item; bufin = (bufin + 1) % BUFSIZE; if (error = sem_post(&mutexbuffer)) return error; if (sem_post(&semitems) == -1) return errno; return 0; }
Counter example #include <pthread.h> static int count = 0; static pthread_mutex_t countlock = PTHREAD_MUTEX_INITIALIZER; int increment(void) { /* increment the counter */ int error; if (error = pthread_mutex_lock(&countlock)) return error; count++; return pthread_mutex_unlock(&countlock); }
Counter Example Cont. int decrement(void) { /* decrement the counter */ int error; if (error = pthread_mutex_lock(&countlock)) return error; count--; return pthread_mutex_unlock(&countlock); } int getcount(int *countp) { /* retrieve the counter */ int error; if (error = pthread_mutex_lock(&countlock)) return error; *countp = count; return pthread_mutex_unlock(&countlock); }
Thread safe library calls int randsafe(double *ranp); #include <pthread.h> #include <stdlib.h> int randsafe(double *ranp) { static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; int error; if (error = pthread_mutex_lock(&lock)) return error; *ranp = (rand() + 0.5)/(RAND_MAX + 1.0); return pthread_mutex_unlock(&lock); }
Using a synchronization flag #include <pthread.h> static int doneflag = 0; static pthread_mutex_t donelock = PTHREAD_MUTEX_INITIALIZER; int getdone(int *flag) { /* get the flag */ int error; if (error = pthread_mutex_lock(&donelock)) return error; *flag = doneflag; return pthread_mutex_unlock(&donelock); } int setdone(void) { /* set the flag */ int error; if (error = pthread_mutex_lock(&donelock)) return error; doneflag = 1; return pthread_mutex_unlock(&donelock); }
Thread Safety • Libraries that have static data • Error reports that print on console • Shared data structures like lists