Synchronization II. q Condition Variables q Semaphores and monitors q Some classical problems q Next time: Deadlocks

Similar documents
Synchronization II. Today. ! Condition Variables! Semaphores! Monitors! and some classical problems Next time. ! Deadlocks

Condition Variables. Dongkun Shin, SKKU

Condition Variables. Dongkun Shin, SKKU

Semaphores Semaphores: A Definition

W4118 Operating Systems. Instructor: Junfeng Yang

Condition Variables. Figure 29.1: A Parent Waiting For Its Child

Semaphores. attention to the previous chapters. And even remembering a few things. You have, right?!

Synchroniza+on II COMS W4118

[537] Semaphores. Tyler Harter

CS 471 Operating Systems. Yue Cheng. George Mason University Fall 2017

Announcements. Class feedback for mid-course evaluations Receive about survey to fill out until this Friday

30. Condition Variables

Semaphores Semaphores: A Definition

Condition Variables. parent: begin child parent: end

Figure 30.1: A Parent Waiting For Its Child What we would like to see here is the following output:

[537] Concurrency Bugs. Tyler Harter

Semaphores. Jinkyu Jeong Computer Systems Laboratory Sungkyunkwan University

Operating System Labs. Yuanbin Wu

Condition Variables. Jinkyu Jeong Computer Systems Laboratory Sungkyunkwan University

Process Synchronization. studykorner.org

Synchronization and Semaphores. Copyright : University of Illinois CS 241 Staff 1

Concurrency and Synchronisation

Data Races and Deadlocks! (or The Dangers of Threading) CS449 Fall 2017

Concurrency and Synchronisation

Learning Outcomes. Concurrency and Synchronisation. Textbook. Concurrency Example. Inter- Thread and Process Communication. Sections & 2.

Operating Systems CMPSCI 377 Spring Mark Corner University of Massachusetts Amherst

Plan. Demos. Next Project. CSCI [4 6]730 Operating Systems. Hardware Primitives. Process Synchronization Part II. Synchronization Part 2

Final review. From threads to file systems

CIS Operating Systems Application of Semaphores. Professor Qiang Zeng Spring 2018

Process Synchronization(2)

Condition Variables CS 241. Prof. Brighten Godfrey. March 16, University of Illinois

Operating Systems. User OS. Kernel & Device Drivers. Interface Programs. Interprocess Communication (IPC)

CS 470 Spring Mike Lam, Professor. Semaphores and Conditions

Synchronization Mechanisms

Process Synchronization(2)

CSci 4061 Introduction to Operating Systems. Synchronization Basics: Locks

Process Synchronization

Operating Systems CMPSC 473. Synchronization February 26, Lecture 12 Instructor: Trent Jaeger

Note: The following (with modifications) is adapted from Silberschatz (our course textbook), Project: Producer-Consumer Problem.

Synchronization and Semaphores. Copyright : University of Illinois CS 241 Staff 1

CS Operating Systems

CS Operating Systems

Operating Systems. Thread Synchronization Primitives. Thomas Ropars.

KING FAHD UNIVERSITY OF PETROLEUM & MINERALS. Information and Computer Science Department. ICS 431 Operating Systems. Lab # 9.

Dealing with Issues for Interprocess Communication

CS 537 Lecture 8 Monitors. Thread Join with Semaphores. Dining Philosophers. Parent thread. Child thread. Michael Swift

Chapter 7: Process Synchronization!

Warm-up question (CS 261 review) What is the primary difference between processes and threads from a developer s perspective?

Lecture Outline. CS 5523 Operating Systems: Concurrency and Synchronization. a = 0; b = 0; // Initial state Thread 1. Objectives.

Synchronization. CS 475, Spring 2018 Concurrent & Distributed Systems

Synchronization Primitives

Locks and semaphores. Johan Montelius KTH

CSE 120. Fall Lecture 6: Semaphores. Keith Marzullo

Process Synchronization(2)

Chapter 6: Process Synchronization

Chapter 7: Process Synchronization. Background. Illustration

Chapter 6: Synchronization. Chapter 6: Synchronization. 6.1 Background. Part Three - Process Coordination. Consumer. Producer. 6.

Process Synchronization

Condition Variables & Semaphores

Chapter 6: Process Synchronization

CSE 4/521 Introduction to Operating Systems

Locks and semaphores. Johan Montelius KTH

Lesson 6: Process Synchronization

High-level Synchronization

Week 3. Locks & Semaphores

CS3502 OPERATING SYSTEMS

Chapter 7: Process Synchronization. Background

Deadlock and Monitors. CS439: Principles of Computer Systems September 24, 2018

PROCESS SYNCHRONIZATION

Topics: Process (Thread) Synchronization (SGG, Ch 5 in 9th Ed Ch 6 in Old Ed) (USP, Chapter 13-14) CS 3733 Operating Systems

Deadlock and Monitors. CS439: Principles of Computer Systems February 7, 2018

CS 153 Lab6. Kishore Kumar Pusukuri

Operating systems and concurrency (B08)

Semaphores. To avoid busy waiting: when a process has to wait, it will be put in a blocked queue of processes waiting for the same event

Semaphores. Semaphores. Semaphore s operations. Semaphores: observations

Chapter 6: Synchronization. Operating System Concepts 8 th Edition,

EI 338: Computer Systems Engineering (Operating Systems & Computer Architecture)

Semaphores (by Dijkstra)

Chapter 5: Process Synchronization. Operating System Concepts Essentials 2 nd Edition

Synchronization. Dr. Yingwu Zhu

Chapter 6: Process Synchronization. Operating System Concepts 8 th Edition,

Process Coordination

Chapter 6: Process Synchronization

Monitors (Deprecated)

Lecture 6 (cont.): Semaphores and Monitors

Synchronization. CSE 2431: Introduction to Operating Systems Reading: Chapter 5, [OSC] (except Section 5.10)

Lecture 5 Threads and Pthreads II

Synchronization Principles

5 Classical IPC Problems

Dining Philosophers, Semaphores

recap, what s the problem Locks and semaphores Total Store Order Peterson s algorithm Johan Montelius 0 0 a = 1 b = 1 read b read a

Chapter 5: Process Synchronization

CS 162 Operating Systems and Systems Programming Professor: Anthony D. Joseph Spring Lecture 8: Semaphores, Monitors, & Condition Variables

Process Synchronization

Interprocess Communication and Synchronization

Concurrency and Synchronisation. Leonid Ryzhyk

Lecture 9: Thread Synchronizations. Spring 2016 Jason Tang

Synchronization Basic Problem:

Introduction to Operating Systems

Semaphore. Originally called P() and V() wait (S) { while S <= 0 ; // no-op S--; } signal (S) { S++; }

Transcription:

Synchronization II q Condition Variables q Semaphores and monitors q Some classical problems q Next time: Deadlocks

Condition variables Locks are not enough to build concurrent programs Many times a thread wants to check whether a condition is true before continuing execution A parent waiting on a child, a consumer on a producer, void *child(void *arg) { printf("child\n"); // XXX how to indicate we are done? return NULL; *From OSTEP int main(int argc, char *argv[]) { printf("parent: begin\n"); pthread_t c; Pthread_create(&c, NULL, child, NULL); // XXX how to wait for child? printf("parent: end\n"); return 0; 2

Condition variables You could wait on a shared variable, but spinning is inefficient volatile int done = 0; void *child(void *arg) { printf("child\n"); done = 1; return NULL; int main(int argc, char *argv[]) { printf("parent: begin\n"); pthread_t c; Pthread_create(&c, NULL, child, NULL); // create child while (!done) ; printf("parent: end\n"); return 0; 3

Condition variables An explicit queue where threads can go when some state is not what they want (waiting on a change) Until some other thread changes the state and informs them of it, signaling on the condition pthread_cond_t c; pthread_cond_wait(pthread_cond_t *c, pthread_mutex_t *m); pthread_cond_signal(pthraed_cond_t *c); 4

Waiting on your child What s with that mutex? pthread_cond_wait(pthread_cond_t *c, pthread_mutex_t *m); Assumes mutex is locked before wait is called Wait must release it and put the thread to sleep, atomically When the thread wakes up, re-acquires the lock before returning All to prevent race condition when a thread is trying to put itself to sleep 5

Waiting on your child Back to parent and child int done = 0; pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER; pthread_cond_t c = PTHREAD_COND_INITIALIZER; int main(int argc, char *argv[]) { pthread_t p; printf( parent: begin\n ); pthread_create(&p, NULL, child, NULL); thr_join(); printf( parent: done\n ); return 0; void *child(void *arg) { printf( child\n ); thr_exit(); return 0; void thr_join() { pthread_mutex_lock(&m); while (done == 0) pthread_cond_wait(&c, &m); pthread_mutex_unlock(&m); void thr_exit() { pthread_mutex_lock(&m); done = 1; pthread_cond_signal(&c); pthread_mutex_unlock(&m); 6

Waiting on your child void thr_join() { pthread_mutex_lock(&m); while (done == 0) pthread_cond_wait(&c, &m); pthread_mutex_unlock(&m); That while doesn t seem strictly necessary, wouldn t an if do wait a bit void thr_exit() { pthread_mutex_lock(&m); done = 1; pthread_cond_signal(&c); pthread_mutex_unlock(&m); Two cases to consider Parent creates the child and continue running Gets the lock, check if done and put itself to sleep Child runs, gets the lock, sets done and signals the parent Parent returns from wait with lock held, unlocks it and is done If child runs first, sets done, signals (nobody is waiting) and returns; parent check child is done and returns 7

Non-working approaches void thr_exit() { pthread_mutex_lock(&m); /* done = 1; */ pthread_cond_signal(&c); pthread_mutex_unlock(&m); void thr_join() { pthread_mutex_lock(&m); /* while (done == 0) */ pthread_cond_wait(&c, &m); pthread_mutex_unlock(&m) void thr_exit() { done = 1; pthread_cond_signal(&c); void thr_join() { if (done == 0) pthread_cond_wait(&c); Do you need done? If the child runs immediately, the signal will be lost Parent will call wait (there s nothing to check) and go to sleep for ever Do you need that mutex? What would happen if the parent is interrupted after checking done but before going to sleep on wait? Child runs, signals nobody (parent is not there yet!) and.. When parent continues it goes to sleep, for ever! 8

Producer/consumer problem Producer-consumer problem, aka bounded buffer Two or more processes & one shared, fixed-size buffer Some put data times into a buffer, others takes them out E.g., Web server with producers taken orders and consumer threads processing them int buff[max]; int fill = 0; int use = 0; int count = 0; void put(int value) { buff[fill] = value; fill = (fill + 1) % MAX; count++; producer producer put() get() consumer consumer int get() { int tmp = buffer[use]; use = (use + 1) % MAX; count--; return tmp; buff[max] 9

Producer/consumer problem Simple solution If buffer empty, producer goes to sleep to be awaken when the consumer has removed one or more items Similarly for the consumer (a first try) cond_t cond; mutex_t mutex; void *producer(void *arg) { pthraed_mutex_lock(&mutex); if (count == MAX) pthread_cond_wait(&cond, &mutex); put(i); pthread_cond_signal(&cond); pthread_mutex_unlock(&mutex); void *consumer(void *arg) { pthraed_mutex_lock(&mutex); if (count == 0) pthread_cond_wait(&cond, &mutex); int tmp = get(i); pthread_cond_signal(&cond); pthread_mutex_unlock(&mutex); 10

A while for an if cond_t cond; mutex_t mutex; 2 consumers/1 producer void *producer(void *arg) { pthraed_mutex_lock(&mutex); if (count == MAX) pthread_cond_wait(&cond, &mutex); put(i); pthread_cond_signal(&cond); pthread_mutex_unlock(&mutex); void *consumer(void *arg) { pthraed_mutex_lock(&mutex); if (count == 0) pthread_cond_wait(&cond, &mutex); int tmp = get(i); pthread_cond_signal(&cond); pthread_mutex_unlock(&mutex); Consumer 1 tries to get item but finds buffer empty, and waits Producer puts an item and signals this, moving C1 to ready queue Consumer 2 sneaks in and gets the one item Now C1 runs; just before returning from the wait it re-acquires the lock, returns and calls get to find an empty buffer!! With condition variables, always use while loops 11

One condition variable is not enough cond_t cond; mutex_t mutex; void *producer(void *arg) { pthraed_mutex_lock(&mutex); while (count == MAX) pthread_cond_wait(&cond, &mutex); put(i); pthread_cond_signal(&cond); pthread_mutex_unlock(&mutex); void *consumer(void *arg) { pthraed_mutex_lock(&mutex); while (count == 0) pthread_cond_wait(&cond, &mutex); int tmp = get(i); pthread_cond_signal(&cond); pthread_mutex_unlock(&mutex); 2 consumers/1 producer and lets MAX = 1 Both consumers try to get the item, find buffer empty and go to sleep Producer puts item, wakes up a consumer (1) and goes to sleep Consumer comes along and gets the one item and signals but who!? Both producer and Consumer 2 are sleeping 12

Finally a solution cond_t empty, fill; mutex_t mutex; Simple solution two condition variables void *producer(void *arg) { pthraed_mutex_lock(&mutex); Producer waits on empty while (count == MAX) and signals fill pthread_cond_wait(&empty, &mutex); put(i); pthread_cond_signal(&fill); pthread_mutex_unlock(&mutex); void *consumer(void *arg) { pthraed_mutex_lock(&mutex); while (count == 0) pthread_cond_wait(&fill, &mutex); int tmp = get(i); pthread_cond_signal(&empty); pthread_mutex_unlock(&mutex); Consumers do the opposite wait on fill and signal empty 13

Semaphores A synchronization primitive Higher level of abstraction than locks, also replacing condition variables Invented by Dijkstra in 68 as part of THE OS Atomically manipulated by two operations sem_wait(sem_t *sem) / P / down(sem) sem_post(sem_t *sem) / V / up(sem) The initial value determine its behavior, so it must be first initialized sem_init(sem_t *sem, int pshared, unsigned int value); Ignored this for now, but basically shared by al threads of a process (0) or by processes through shared memory (!=0) 14

Blocking in semaphores Each semaphore has an associated queue of processes/threads sem_wait / P (prolaag try to reduce ) If sem was available (>0), decrement the value of the semaphore by 1 and let it run Else, place it on the associated queue sem_post / V (verhogen increase in Dutch) If thread(s) are waiting on the queue, unblock one, placing it in the ready queue Else, increment the value of the semaphore by one Remembering for next time sem_wait is called 15

Semaphores as locks binary semaphores sem_t m; sem_init(&m, 0, 1); Why 1? Look at the definition of wait and post sem_wait(&m); /* critical section */ sem_post(&m); int sem_wait(sem_t *s){ s.value--; wait in a queue of s until (s.value > 0); int sem_post(sem_t *s) { s.value++; if there are 1+ threads waiting wake one thread up; So, if m = 1 the first thread will go in and decrement its value, the following thread will wait until the thread inside increments it within sem_post() 16

Semaphores as condition variables Waiting on a condition, as when parent waits for child to terminate sem_t s; void *child(void *arg) { printf( child\n ); sem_post(&s); return NULL; int main(int argc, char*argv[]) Why { 0? sem_init(&s, 0, 0); printf( parent: begin\n ); pthread_t c; pthread_create(c, NULL, child, NULL); sem_wait(&s); printf( parent: end\n ); return 0; So, if m = 0 and parent runs, will wait until the child runs and sets value to 1; If child runs first, the value will be 1 and the parent will go on without waiting 17

Semaphores Producer/consumer v1 sem_t empty; sem_t full; sem_t mutex; void *producer(void *arg) { sem_wait(&empty); put(i); sem_post(&full); void *consumer(void *arg) { sem_wait(&full); int tmp = get(); sem_post(&empty); Yeap, those are CSs void put(int value) { buff[fill] = value; fill = (fill + 1) % MAX; int get() { int tmp = buffer[use]; use = (use + 1) & MAX; return tmp; int main... sem_init(&empty, 0, MAX); /* MAX buffers are empty... */ sem_init(&full, 0, 0); /* and 0 are full */... 18

Semaphores Producer/consumer sem_t empty; sem_t full; sem_t mutex; void *producer(void *arg) { sem_wait(&empty); sem_wait(&mutex); put(i); sem_post(&mutex); sem_post(&full); void *consumer(void *arg) { sem_wait(&full); sem_wait(&mutex); int tmp = get(); sem_post(&mutex); sem_post(&empty); Protect the critical section Protect the critical section int main... sem_init(&empty, 0, MAX); /* MAX buffers are empty... */ sem_init(&full, 0, 0); /* and 0 are full */ sem_init(&mutex, 0, 1); /* set to 1, it s a lock */... 19

Readers-writers problem The need for a more flexible type of lock, imagine a database or a simple linked list Not problem with multiple readers allowed at once Only one writer allowed at a time If writers is in, nobody else is First reader blocks the writer from entering typedef struct _rwlock_t { sem_t lock; sem_t writelock; int readers; rwlock_t; void rwlock_acquire_writelock(rwlock_t *rw) { sem_wait(&rw->writelock); void rwlock_release_writelock(rwlock_t *rw) { sem_post(&rw->writelock); Simple, only a single writer allowed void rwlock_acquire_readlock(rwlock_t *rw) { sem_wait(&rw->lock); rw->readers++; if (rw->readers == 1) sem_wait(&rw->writelock); sem_post(&rw->lock); void rwlock_release_readlock(rwlock_t *rw) { sem_wait(&rw->lock); rw->readers--; if (rw->readers == 0) sem_post(&rw->writelock); sem_post(&rw->lock); Last reader lets the writer in 20

Semaphores and deadlocks Semaphores solves most synchronization problems But no control or guarantee of proper usage Minor change? void *consumer(void *arg) { sem_wait(&full); sem_wait(&mutex); int tmp = get(); sem_post(&mutex); sem_post(&empty); void *producer(void *arg) { sem_wait(&empty); sem_wait(&mutex); put(i); sem_post(&mutex); sem_post(&full); void *consumer(void *arg) { sem_wait(&mutex); sem_wait(&full); int tmp = get(); sem_post(&empty); sem_post(&mutex); void *producer(void *arg) { sem_wait(&mutex); sem_wait(&empty); put(i); sem_post(&full); sem_post(&mutex); 21

Watch for deadlocks Deadlock! Consumer holds the mutex and goes to sleep, to wait for the producer to put something Producer can t put anything because consumer holds the lock! void *consumer(void *arg) { sem_wait(&mutex); sem_wait(&full); int tmp = get(); sem_post(&empty); sem_post(&mutex); void *producer(void *arg) { sem_wait(&mutex); sem_wait(&empty); put(i); sem_post(&full); sem_post(&mutex); 22

Issues with semaphores Solves most synchronization problems, but: We have seen, no control over their use, no guarantee of proper usage (our deadlock example) Semaphores are essentially shared global variables Can be accessed from anywhere (bad software engineering) No connection between the semaphore & the data controlled by it Used for both critical sections and for coordination (scheduling) 23

Monitors Higher level synchronization primitive Monitors A programming language construct Set of procedures, variables and data structures Monitor s internal data structures are private Monitors and mutual exclusion Only one thread active at a time Queue of threads Shared data FuncA One thread at a time in the monitor FuncB FuncC 24

Monitors To enforce sequences of events Condition variables Only accessed from within the monitor Three operations wait, signal & broadcast Wait Atomically releases the lock Suspends execution of the calling thread, places it in the waiting queue When the calling thread is re-enable, it requires the lock before returning from the wait A thread that waits steps outside the monitor A condition variable is memoryless, no internal state (the shared object defines its own); so, wait is not a counter signal may get lost 25

Monitors Signal Takes a waiting thread off the condition variable s waiting queue and marks it as eligible to run Broadcast Like signal but for all threads waiting What happen after the signal? Hoare process awakened run Brinch Hansen process signaling must exit Mesa process signaling continues to run As a programmer always check the condition after being woken! i.e., call within a while while (predicateonstatevar( )) wait(&lock); 26

Producer/consumer Monitor ProdCons { condition full, empty; int count; void insert(int item) { if (count == N) wait(full); insert_item(item); count++; // if buffer was empty, wakeup consumer if (count == 1) signal(empty) int remove(void) { if count == 0 wait(empty); return(remove_item); count--; // if buffer was full, wakeup producer if (count == N 1) signal(full); count := 0; void consumer() { while TRUE { item = ProdCons.remove; consume_item(item); void producer() { while TRUE { item = produce_item; ProdCons.insert(item); 27

Monitors Monitors and mutual exclusion Only one process active at a time how? Synchronization code is added by the compiler (or the programmer using locks) Clear similarities between the two you can use one to implement the other 28

Monitors and semaphores A semaphore implemented as a monitor Monitor class Semaphore { int s; Semaphore(int value) { s = value; void down() { while (s <= 0) wait(); s--; void up() { s++; signal(); Using it as a binary semaphore Semaphore s(1); s.down(); /* Critical section */ s.up(); 29

Coming up Deadlocks How deadlock arise and what you can do about them 30

Dining philosophers Another one by Dijkstra Philosophers eat/think To eat, a philosopher needs 2 chopsticks Picks one at a time How to prevent deadlock and starvation #define N 5 void philosopher(int i) { while (TRUE) { think(); take_chopstick(i); take_chopstick((i+1)%n); eat(); put_chopstick(i); put_chopstick((i+1)%n); Nonsolution Now: Everybody takes the left chopstick! Why not just protect all this with a mutex? 31

Dining philosophers example state[] too keep track of philosopher s (eating, thinking, hungry) s[] array of semaphores, one per philosopher state void philosopher(int i) { while(true) { think(); take_chopstick(i); eat(); put_chopstick(i); void put_chopstick(int i) { sem_wait(&mutex); state[i] = THINKING; test(left); test(right); sem_post(&mutex); void take_chopstick(int i) { sem_wait(&mutex); state[i] = HUNGRY; test(i); sem_post(&mutex); sem_wait(&s[i]); void test(int i) { if ((state[i] == hungry && state[left]!= eating && state[right]!= eating) { state[i] = EATING; sem_post(&s[i]); 32