1 / 25

Condition variable

Condition variable. Announcements. Quiz Getting the big picture Programming assignments Cooperation Lecture is cut 20 mins short for Quiz and in-class activity. . Today. Races Deadlocks Dining Philosopher's Problem Condition Variable. One Worry : Races.

brit
Download Presentation

Condition variable

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Condition variable

  2. Announcements • Quiz • Getting the big picture • Programming assignments • Cooperation • Lecture is cut 20 mins short for Quiz and in-class activity.

  3. Today • Races • Deadlocks • Dining Philosopher's Problem • Condition Variable

  4. One Worry: Races • A raceoccurs when correctness of the program depends on one thread reaching point x before another thread reaches point y /* a threaded program with a race */ int main() { pthread_ttid[N]; inti; for (i = 0; i < N; i++) Pthread_create(&tid[i], NULL, thread, &i); for (i = 0; i < N; i++) Pthread_join(tid[i], NULL); exit(0); } /* thread routine */ void *thread(void *vargp) { intmyid = *((int *)vargp); printf("Hello from thread %d\n", myid); return NULL; } race.c

  5. Race Elimination • Make sure don’t have unintended sharing of state /* a threaded program without the race */ intmain() { pthread_ttid[N]; inti; for (i = 0; i < N; i++) { int*valp = malloc(sizeof(int)); *valp = i; Pthread_create(&tid[i], NULL, thread, valp); } for (i = 0; i < N; i++) Pthread_join(tid[i], NULL); exit(0); } /* thread routine */ void *thread(void *vargp) { intmyid = *((int *)vargp); free(vargp); printf("Hello from thread %d\n", myid); return NULL; } norace.c

  6. Today • Races • Deadlocks • Dining Philosopher's Problem • Condition Variable

  7. Another Worry: Deadlock • Def: A process is deadlockediff it is waiting for a condition that will never be true. • Typical Scenario • Processes 1 and 2 needs two resources (A and B) to proceed • Process 1 acquires A, waits for B • Process 2 acquires B, waits for A • Both will wait forever! • Analogous to a traffic gridlock

  8. Deadlocking With Semaphores int main() { pthread_ttid[2]; Sem_init(&mutex[0], 0, 1); /* mutex[0] = 1 */ Sem_init(&mutex[1], 0, 1); /* mutex[1] = 1 */ Pthread_create(&tid[0], NULL, count, (void*) 0); Pthread_create(&tid[1], NULL, count, (void*) 1); Pthread_join(tid[0], NULL); Pthread_join(tid[1], NULL); printf("cnt=%d\n", cnt); exit(0); } void *count(void *vargp) { int i; int id = (int) vargp; for (i = 0; i < NITERS; i++) { P(&mutex[id]); P(&mutex[1-id]); cnt++; V(&mutex[id]); V(&mutex[1-id]); } return NULL; } Tid[0]: P(s0); P(s1); cnt++; V(s0); V(s1); Tid[1]: P(s1); P(s0); cnt++; V(s1); V(s0);

  9. Deadlock Visualized in Progress Graph Thread 2 Locking introduces the potential for deadlock: waiting for a condition that will never be true Any trajectory that enters the deadlock region will eventually reach the deadlock state, waiting for either s0 or s1 to become nonzero Other trajectories luck out and skirt the deadlock region Unfortunate fact: deadlock is often nondeterministic Deadlock state V(s0) Forbidden region for s0 V(s1) P(s0) Forbidden region for s1 Deadlock region P(s1) Thread 1 P(s0) P(s1) V(s0) V(s1) s0=s1=1

  10. Avoiding Deadlock Acquire shared resources in same order int main() { pthread_t tid[2]; Sem_init(&mutex[0], 0, 1); /* mutex[0] = 1 */ Sem_init(&mutex[1], 0, 1); /* mutex[1] = 1 */ Pthread_create(&tid[0], NULL, count, (void*) 0); Pthread_create(&tid[1], NULL, count, (void*) 1); Pthread_join(tid[0], NULL); Pthread_join(tid[1], NULL); printf("cnt=%d\n", cnt); exit(0); } void *count(void *vargp) { int i; int id = (int) vargp; for (i = 0; i < NITERS; i++) { P(&mutex[0]); P(&mutex[1]); cnt++; V(&mutex[id]); V(&mutex[1-id]); } return NULL; } Tid[0]: P(s0); P(s1); cnt++; V(s0); V(s1); Tid[1]: P(s0); P(s1); cnt++; V(s1); V(s0);

  11. Avoided Deadlock in Progress Graph Thread 2 No way for trajectory to get stuck Processes acquire locks in same order Order in which locks released immaterial V(s0) Forbidden region for s0 V(s1) P(s0) Forbidden region for s1 P(s1) Thread 1 P(s0) P(s1) V(s0) V(s1) s0=s1=1

  12. Threads Summary • Threads provide another mechanism for writing concurrent programs • Threads are growing in popularity • Somewhat cheaper than processes • Easy to share data between threads • However, the ease of sharing has a cost: • Easy to introduce subtle synchronization errors • Tread carefully with threads! • For more info: • D. Butenhof, “Programming with Posix Threads”, Addison-Wesley, 1997

  13. Dining Philosopher’s Problem(Dijkstra ’71) Philosophers eat/think Eating needs two forks Pick one fork at a time Captures the concept of multiple threadscompeting for shared resources

  14. Dining Philosopher’s Problem • Thinking about philosophers makes it easier to think abstractly. • The philosophers are very logical • They want to settle on a shared policy that all can apply concurrently • They are hungry: we should let everyone eat (eventually) • The policy should be totally fair. • Design an algorithm that the philosophers can follow that insures that none starves as long as each philosopher eventually stops eating, and such that the maximum number of philosophers can eat at once.

  15. Wrong design void philosopher() { while(1) { sleep(); get_left_fork(); get_right_fork(); eat(); put_left_fork(); put_right_fork(); } } Other (inefficient) ideas: use a binary semaphore before getting the forks Recommended reading: http://www.isi.edu/~faber/cs402/notes/lecture8.pdf

  16. What can go wrong? • Starvation: Leaving some philosopher hungry (for a long time) in some situation • Deadlock: All the philosophers waits or gets “stuck”; nobody can make progress • Livelock: Everyone does something endlessly (e.g., infinite loop) without ever eating! • Deadlock  Starvation but not vice versa

  17. Solution 1: test (get_fork blocks until you can eat) void get_forks(inti) { P(mutex); state[i] = HUNGRY; test(i); // try to acquire two forks V(mutex); P(s[i]); // wait if you can’t eat } void put_forks(inti) { P(mutex); state[i]= THINKING; test(LEFT(i)); // see if LEFT can eat test(RIGHT(i)); // see if RIGHT can eat V(mutex); } void philosopher(int process) { while(1) { think(); get_forks(process); eat(); put_forks(process); } } #define N 5 /* Number of philosphers */ #define RIGHT(i) (((i)+1) %N) #define LEFT(i) (((i)==N) ? 0 : (i)+1) typedefenum { THINKING, HUNGRY, EATING } phil_state; phil_state state[N]; semaphore mutex =1; semaphore s[N]; /* one per philosopher, all 0 */ void test(inti) { if ( state[i] == HUNGRY && state[LEFT(i)] != EATING && state[RIGHT(i)] != EATING ) { state[i] = EATING; V(s[i]); } }

  18. Solution 2 void philosopher(int process) { while(1) { think(); get_forks(process); eat(); put_forks(); } } void get_forks(inti) { state[i] = HUNGRY; while ( state[i] == HUNGRY ) { P(mutex); if ( state[i] == HUNGRY && state[LEFT] != EATING && state[RIGHT(i)] != EATING ) { state[i] = EATING; V(s[i]); } V(mutex); P(s[i]); } } void put_forks(inti) { P(mutex); state[i]= THINKING; if ( state[LEFT(i)] == HUNGRY ) V(s[LEFT(i)]); if ( state[RIGHT(i)] == HUNGRY) V(s[RIGHT(i)]); V(mutex); }

  19. Today • Races • Deadlocks • Dining Philosopher's Problem • Condition Variable

  20. Difficulties in using Semaphores • Semaphores provide a very general mechanism for synchronization. • The power of semaphores derives from calls to P() and V() that are unmatched. • E.g., reader/writer and dining phil. • Unlike mutex (locks) where we lock() and unlock() • This means that it’s very tricky to get it right (e.g., no single fixed pattern of use and/or more than one semaphores).

  21. Condition Variables • Condition variablesis a synchronization primitive that helps us model events (rather than resources in the case of semaphores). • A condition variable represents some condition that a thread can: • Wait on, until the condition occurs; or • Notify other waiting threads that the condition has occur • It provides a place to wait (queue).

  22. Condition Variables • Operations on condition variables: • wait() -- Block until another thread calls signal() or broadcast() on the CV • signal() -- Wake up one thread waiting on the CV • broadcast() -- Wake up all threads waiting on the CV • Pthread • pthread_cond_wait(pthread_cond_t *c, pthread_mutex_t *m); • pthread_cond_signal(pthread_cond_t *c); • pthread_cond_broadcast (pthread_cond_t *c); • Used with mutex

  23. Broadcast • The pthread_cond_broadcast() function is used whenever the shared-variable state has been changed in a way that more than one thread can proceed with its task. • Single producer/multiple consumer problem • The producer would notify all consumers that might be waiting; more throughput on a multi-processor. • Read-write lock. • Wakes up all waiting readers when a writer releases its lock. Recommended readinghttp://pages.cs.wisc.edu/~remzi/OSFEP/threads-cv.pdf

  24. Producer and consumer • Important to use while statement to check the condition after waking up. It handles spurious wakeup. cond_t empty, fill; void produce(int item) { mutex_lock(&mutex); while (count == MAX) cond_wait(&empty, &mutex); put(item); // put an item in the circular buffer cond_signal(&fill); // signal an item is filled mutex_unlock(&mutex); } int consumer() { mutex_lock(&mutex); while (count == 0) cond_wait(&fill, &mutex); int item = get(); cond_signal(&empty); mutex_unlock(&mutex); return item; }

  25. Next Lecture • So far we have learned basic concepts in Operating System. • This is not an OS class • But, most of you didn’t take OS. • We will begin to talk more about distributed systems.

More Related