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

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

Introduction to parallel computing

Synchronization Primitives

Multithreading Programming II

POSIX Threads. Paolo Burgio

real time operating systems course

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

Locks and semaphores. Johan Montelius KTH

Real Time Operating Systems and Middleware

CSci 4061 Introduction to Operating Systems. Synchronization Basics: Locks

CS-345 Operating Systems. Tutorial 2: Grocer-Client Threads, Shared Memory, Synchronization

Process Synchronization

Locks and semaphores. Johan Montelius KTH

Synchronization Mechanisms

CSCE 313: Introduction to Computer Systems

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

Posix Threads (Pthreads)

CS 153 Lab6. Kishore Kumar Pusukuri

CSC Systems Programming Fall Lecture - XIV Concurrent Programming. Tevfik Ko!ar. Louisiana State University. November 2nd, 2010

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

Multi-threaded Programming

CS345 Opera,ng Systems. Φροντιστήριο Άσκησης 2

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

Week 3. Locks & Semaphores

POSIX Semaphores. Operations on semaphores (taken from the Linux man page)

Threads. Jo, Heeseung

CS 470 Spring Mike Lam, Professor. Semaphores and Conditions

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

POSIX Threads. HUJI Spring 2011

Lecture 4. Threads vs. Processes. fork() Threads. Pthreads. Threads in C. Thread Programming January 21, 2005

Condition Variables. Jinkyu Jeong Computer Systems Laboratory Sungkyunkwan University

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

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

Lecture 9: Thread Synchronizations. Spring 2016 Jason Tang

ANSI/IEEE POSIX Standard Thread management

Ricardo Rocha. Department of Computer Science Faculty of Sciences University of Porto

Lecture 18. Log into Linux. Copy two subdirectories in /home/hwang/cs375/lecture18/ $ cp r /home/hwang/cs375/lecture18/*.

Resource Access Control (2) Real-Time and Embedded Systems (M) Lecture 14

Network Programming TDC 561

Process Synchronization (Part I)

COSC 6374 Parallel Computation. Shared memory programming with POSIX Threads. Edgar Gabriel. Fall References

Multithread Programming. Alexandre David

Pthreads. Jin-Soo Kim Computer Systems Laboratory Sungkyunkwan University

Pthreads (2) Dong-kun Shin Embedded Software Laboratory Sungkyunkwan University Embedded Software Lab.

Threads. Jo, Heeseung

Operating System Labs. Yuanbin Wu

Threads need to synchronize their activities to effectively interact. This includes:

CSE 421/521 - Operating Systems Fall 2011 Recitations. Recitation - III Networking & Concurrent Programming Prof. Tevfik Kosar. Presented by...

[537] Semaphores. Tyler Harter

Concurrent Server Design Multiple- vs. Single-Thread

Paralleland Distributed Programming. Concurrency

Introduc)on to pthreads. Shared memory Parallel Programming

POSIX PTHREADS PROGRAMMING

Concurrency, Parallel and Distributed

TCSS 422: OPERATING SYSTEMS

Final Examination (Fall 2016) (Section 1)

W4118 Operating Systems. Instructor: Junfeng Yang

Synchronization. Semaphores implementation

Synchroniza+on II COMS W4118

Condition Variables. Dongkun Shin, SKKU

Process Synchronization(2)

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

The course that gives CMU its Zip! Concurrency II: Synchronization Nov 14, 2000

Real Time Operating System Support for Concurrency

Synchronization. Dr. Yingwu Zhu

Process Synchronization(2)

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

20-EECE-4029 Operating Systems Spring, 2015 John Franco

CS 345 Operating Systems. Tutorial 2: Treasure Room Simulation Threads, Shared Memory, Synchronization

Pre-lab #2 tutorial. ECE 254 Operating Systems and Systems Programming. May 24, 2012

Operating systems and concurrency (B08)

Systems Programming/ C and UNIX

Condition Variables. Dongkun Shin, SKKU

Process Synchronization(2)

CS 453/552: Operating Systems Midterm Examination

Access to the same variable

Global variables and resources are shared between threads within the same process. Each thread has its own stack and program counter (see Fig 2-7).

POSIX threads CS 241. February 17, Copyright University of Illinois CS 241 Staff

LSN 13 Linux Concurrency Mechanisms

Thread and Synchronization

Process Synchronization. studykorner.org

CS 333 Introduction to Operating Systems. Class 3 Threads & Concurrency. Jonathan Walpole Computer Science Portland State University

Faculté Polytechnique

Operating Systems CMPSCI 377 Spring Mark Corner University of Massachusetts Amherst

Shared Memory: Virtual Shared Memory, Threads & OpenMP

Introduction to PThreads and Basic Synchronization

CS 333 Introduction to Operating Systems. Class 3 Threads & Concurrency. Jonathan Walpole Computer Science Portland State University

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

Lecture 19: Shared Memory & Synchronization

Threads. Jinkyu Jeong Computer Systems Laboratory Sungkyunkwan University

Interlude: Thread API

Chapter 4 Concurrent Programming

Interprocess Communication and Synchronization

Concurrency and Synchronization. ECE 650 Systems Programming & Engineering Duke University, Spring 2018

Parallel Programming with Threads

Semaphores Semaphores: A Definition

Carnegie Mellon. Bryant and O Hallaron, Computer Systems: A Programmer s Perspective, Third Edition

POSIX / System Programming

Agenda. Process vs Thread. ! POSIX Threads Programming. Picture source:

CS 333 Introduction to Operating Systems Class 4 Concurrent Programming and Synchronization Primitives

Transcription:

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

Synchronization Primatives Counting Semaphores Permit a limited number of threads to execute a section of the code Binary Semaphores - Mutexes Permit only one thread to execute a section of the code Condition Variables Communicate information about the state of shared data Copyright : University of Illinois CS 241 Staff 2

POSIX Semaphores Named Semaphores Provides synchronization between unrelated process and related process as well as between threads Kernel persistence System-wide and limited in number Uses sem_open Unnamed Semaphores Provides synchronization between threads and between related processes Thread-shared or process-shared Uses sem_init Copyright : University of Illinois CS 241 Staff 3

POSIX Semaphores Data type Semaphore is a variable of type sem_t Include <semaphore.h> Atomic Operations int sem_init(sem_t *sem, int pshared, unsigned value); int sem_destroy(sem_t *sem); int sem_post(sem_t *sem); int sem_trywait(sem_t *sem); int sem_wait(sem_t *sem); Copyright : University of Illinois CS 241 Staff 4

Unnamed Semaphores #include <semaphore.h> int sem_init(sem_t *sem, int pshared, unsigned value); Initialize an unnamed semaphore Returns 0 on success -1 on failure, sets errno Parameters sem: Target semaphore pshared: You cannot make a copy of a semaphore variable!!! 0: only threads of the creating process can use the semaphore Non-0: other processes can use the semaphore value: Initial value of the semaphore Copyright : University of Illinois CS 241 Staff 5

Sharing Semaphores Sharing semaphores between threads within a process is easy, use pshared==0 A non-zero pshared allows any process that can access the semaphore to use it Places the semaphore in the global (OS) environment Forking a process creates copies of any semaphore it has Note: unnamed semaphores are not shared across unrelated processes Copyright : University of Illinois CS 241 Staff 6

sem_init can fail On failure sem_init returns -1 and sets errno errno EINVAL ENOSPC EPERM cause Value > sem_value_max Resources exhausted Insufficient privileges sem_t sema; if (sem_init(&sema, 0, 1) == -1) perror( Failed to initialize semaphore sema ); Copyright : University of Illinois CS 241 Staff 7

Semaphore Operations #include <semaphore.h> int sem_destroy(sem_t *sem); Destroy an semaphore Returns 0 on success -1 on failure, sets errno Parameters sem: Target semaphore Notes Can destroy a sem_t only once Destroying a destroyed semaphore gives undefined results Destroying a semaphore on which a thread is blocked gives undefined results Copyright : University of Illinois CS 241 Staff 8

Semaphore Operations #include <semaphore.h> int sem_post(sem_t *sem); Unlock a semaphore - same as signal Returns 0 on success -1 on failure, sets errno (== EINVAL if semaphore doesn t exist) Parameters sem: Target semaphore sem > 0: no threads were blocked on this semaphore, the semaphore value is incremented sem == 0: one blocked thread will be allowed to run Copyright : University of Illinois CS 241 Staff 9

Semaphore Operations #include <semaphore.h> int sem_wait(sem_t *sem); Lock a semaphore Blocks if semaphore value is zero Returns 0 on success -1 on failure, sets errno (== EINTR if interrupted by a signal) Parameters sem: Target semaphore sem > 0: thread acquires lock sem == 0: thread blocks Copyright : University of Illinois CS 241 Staff 10

Semaphore Operations #include <semaphore.h> int sem_trywait(sem_t *sem); Test a semaphore s current condition Does not block Returns 0 on success -1 on failure, sets errno (== AGAIN if semaphore already locked) Parameters sem: Target semaphore sem > 0: thread acquires lock sem == 0: thread returns Copyright : University of Illinois CS 241 Staff 11

Good Practices int main(void) {... /* Initialize mutex */ result = sem_init(&cnt_mutex, 0, 1); if (result < 0) exit(-1); Check for errors on each call... /* Clean up the semaphore that we're done with */ result = sem_destroy(&cnt_mutex); assert(result == 0); Clean up resources Copyright : University of Illinois CS 241 Staff 12

Why bother checking for errors? Without error handling, your code might Crash rather than exiting gracefully Keep working for a while, crash later Sometimes fail randomly, but usually work fine Hard to reproduce: even harder to debug Fail when it might have recovered from the error cleanly! At a minimum, error handling converts a messy failure into a clean failure Program terminates, but you know what caused it to terminate Copyright : University of Illinois CS 241 Staff 13

Some errors are recoverable void * worker( void *ptr ) { int i; for (i = 0; i < ITERATIONS_PER_THREAD; i++) { while (sem_wait(&cnt_mutex) < 0) if (errno!= EINTR) exit(-1); cnt++; if (sem_post(&cnt_mutex) < 0) exit(-1); Copyright : University of Illinois CS 241 Staff 14

Back to the counter... #include <stdio.h> #include <stdlib.h> #include <pthread.h> #include <assert.h> How can we fix this using semaphores? #define NUM_THREADS 2 #define ITERATIONS_PER_THREAD 50000 int cnt = 0; void * worker( void *ptr ) { int i; for (i = 0; i < ITERATIONS_PER_THREAD; i++) cnt++; Copyright : University of Illinois CS 241 Staff 15

Example: bank balance Protect shared variable balance with a semaphore when used in: decshared Decrements current value of balance incshared increments the balance Copyright : University of Illinois CS 241 Staff 17

Example: bank balance int decshared() { while (sem_wait(&balance_sem) == -1) if (errno!= EINTR) return -1; balance--; return sem_post(&balance_sem); int incshared() { while (sem_wait(&balance_sem) == -1) if (errno!= EINTR) return -1; balance++; return sem_post(&balance_sem); Copyright : University of Illinois CS 241 Staff 18

Example: bank balance #include <errno.h> #include <semaphore.h> static int balance = 0; static sem_t bal_sem; pshared int initshared(int val) { if (sem_init(&bal_sem, 0, 1) == -1) return -1; balance = val; return 0; value Copyright : University of Illinois CS 241 Staff 19

Example: bank balance int decshared() { while (sem_wait(&bal_sem) == -1) if (errno!= EINTR) return -1; balance--; return sem_post(&bal_sem); int incshared() { while (sem_wait(&bal_sem) == -1) if (errno!= EINTR) return -1; balance++; return sem_post(&bal_sem); Which one is going first? Copyright : University of Illinois CS 241 Staff 20

Advanced Semaphores int semget(key_t key, int nsems, int semflg); Get set of semaphores int semop(int semid, struct sembuf *sops, unsigned int nsops); Atomically perform a user-defined array of semaphore operations on the set of semaphores Copyright : University of Illinois CS 241 Staff 21

Pthread Synchronization Two primitives Mutex Semaphore with maximum value 1 Locked Some thread holds the mutex Unlocked No thread holds the mutex Condition variable Provides a shared signal Combined with a mutex for synchronization Copyright : University of Illinois CS 241 Staff 22

Creating a mutex #include <pthread.h> int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr); Initialize a pthread mutex: the mutex is initially unlocked Returns 0 on success Error number on failure Parameters EAGAIN: The system lacked the necessary resources; ENOMEM: Insufficient memory ; EPERM: Caller does not have privileges; EBUSY: An attempt to reinitialise a mutex; EINVAL: The value specified by attr is invalid mutex: Target mutex attr: NULL: the default mutex attributes are used Non-NULL: initializes with specified attributes Copyright : University of Illinois CS 241 Staff 23

Creating a mutex Default attributes Use PTHREAD_MUTEX_INITIALIZER Statically allocated Equivalent to dynamic initialization by a call to pthread_mutex_init() with parameter attr specified as NULL No error checks are performed Copyright : University of Illinois CS 241 Staff 24

Destroying a mutex #include <pthread.h> int pthread_mutex_destroy(pthread_mutex_t *mutex); Destroy a pthread mutex Returns 0 on success Error number on failure Parameters EBUSY: An attempt to re-initialise a mutex; EINVAL: The value specified by attr is invalid mutex: Target mutex Copyright : University of Illinois CS 241 Staff 25

Locking/unlocking a mutex #include <pthread.h> int pthread_mutex_lock(pthread_mutex_t *mutex); int pthread_mutex_trylock(pthread_mutex_t *mutex); int pthread_mutex_unlock(pthread_mutex_t *mutex); Returns 0 on success Error number on failure EBUSY: already locked; EINVAL: Not an initialised mutex; EDEADLK: The current thread already owns the mutex; EPERM: The current thread does not own the mutex Copyright : University of Illinois CS 241 Staff 26

Simple Example #include <pthread.h> #include <stdio.h> #include <stdlib.h> static pthread_mutex_t my_lock = PTHREAD_MUTEX_INITIALIZER; void *mythread(void *ptr) { long int i,j; while (1) { pthread_mutex_lock (&my_lock); int main (int argc, char *argv[]) { pthread_t thread[2]; pthread_create(&thread[0], NULL, mythread, (void *)0); pthread_create(&thread[1], NULL, mythread, (void *)1); getchar(); for (i=0; i<10; i++) { printf ("Thread %d\n", int) ptr); for (j=0; j<50000000; j++); pthread_mutex_unlock (&my_lock); for (j=0; j<50000000; j++); Copyright : University of Illinois CS 241 Staff 27

Condition Variables Goal: Wait for a specific event to happen Event depends on state shared with multiple threads Solution: condition variables Names an event Internally, is a queue of threads waiting for the event Basic operations Wait for event Signal occurrence of event to one waiting thread Signal occurrence of event to all waiting threads Signaling, not mutual exclusion Condition variable is intimately tied to a mutex Copyright : University of Illinois CS 241 Staff 28

Condition Variables Allows threads to synchronize based upon the actual value of data Without condition variables Threads continually poll to check if the condition is met Signaling, not mutual exclusion A mutex is needed to synchronize access to the shared data Each condition variable is associated with a single mutex Wait atomically unlocks the mutex and blocks the thread Signal awakens a blocked thread Copyright : University of Illinois CS 241 Staff 29

Creating a Condition Variable Similar to pthread mutexes int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr); int pthread_cond_destroy(pthread_cond_t *cond); pthread_cond_t cond = PTHREAD_COND_INITIALIZER; Copyright : University of Illinois CS 241 Staff 30

Using a Condition Variable Waiting Block on a condition variable. Called with mutex locked by the calling thread Atomically release mutex and cause the calling thread to block on the condition variable On return, mutex is locked again int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex); int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec *abstime); Copyright : University of Illinois CS 241 Staff 31

Using a Condition Variable Signaling int pthread_cond_signal(pthread_cond_t *cond); unblocks at least one of the blocked threads int pthread_cond_broadcast(pthread_cond_t *cond); unblocks all of the blocked threads Signals are not saved Must have a thread waiting for the signal or it will be lost Copyright : University of Illinois CS 241 Staff 32

Condition Variable: Why do we need the mutex? pthread_mutex_lock(&mutex); /* lock mutex */ while (!predicate) { /* check predicate */ pthread_cond_wait(&condvar, &mutex); /* go to sleep recheck pred on awakening */ pthread_mutex_unlock(&mutex); /* unlock mutex */ pthread_mutex_lock(&mutex); /* lock the mutex */ predicate=1; /* set the predicate */ pthread_cond_broadcast(&condvar); /* wake everyone up */ pthread_mutex_unlock(&mutex); /* unlock the mutex */ Copyright : University of Illinois CS 241 Staff 33

Condition Variable: No mutex! pthread_mutex_lock(&mutex); /* lock mutex */ while (!predicate) { /* check predicate */ pthread_mutex_unlock(&mutex); /* unlock mutex */ pthread_cond_wait(&condvar); /* go to sleep recheck pred on awakening */ pthread_mutex_lock(&mutex); /* lock mutex */ pthread_mutex_unlock(&mutex); /* unlock mutex */ What can happen here? pthread_mutex_lock(&mutex); /* lock the mutex */ predicate=1; /* set the predicate */ pthread_cond_broadcast(&condvar); /* wake everyone up */ pthread_mutex_unlock(&mutex); /* unlock the mutex */ Copyright : University of Illinois CS 241 Staff 34

Condition Variable: Why do we need the mutex? Separating the condition variable from the mutex Thread goes to sleep when it shouldn't Problem pthread_mutex_unlock() and pthread_cond_wait() are not guaranteed to be atomic Joining condition variable and mutex Call to pthread_cond_wait() unlocks the mutex UNIX kernel can guarantee that the calling thread will not miss the broadcast Copyright : University of Illinois CS 241 Staff 38

Condition Variable: Why do we need the while loop? Why not just use an if statement? while (items_in_buffer == 0) { cond_wait(&item_available, &m);... if (items_in_buffer == 0) { cond_wait(&item_available, &m);... Copyright : University of Illinois CS 241 Staff 39

Using a Condition Variable: Challenges Call pthread_cond_signal() before calling pthread_cond_wait() Logical error waiting thread will not catch the signal Fail to lock the mutex before calling pthread_cond_wait() May cause it NOT to block Fail to unlock the mutex after calling pthread_cond_signal() May not allow a matching pthread_cond_wait() routine to complete (it will remain blocked). Copyright : University of Illinois CS 241 Staff 42

Example without Condition Variables int data_avail = 0; pthread_mutex_t data_mutex = PTHREAD_MUTEX_INITIALIZER; void *producer(void *) { pthread_mutex_lock(&data_mutex); <Produce data> <Insert data into queue;> data_avail=1; pthread_mutex_unlock(&data_mutex); Copyright : University of Illinois CS 241 Staff 43

Example without Condition Variables void *consumer(void *) { while(!data_avail ); /* do nothing */ pthread_mutex_lock(&data_mutex); <Extract data from queue;> if (queue is empty) data_avail = 0; Busy Waiting! pthread_mutex_unlock(&data_mutex); <Consume Data> Copyright : University of Illinois CS 241 Staff 44

Example with Condition Variables int data_avail = 0; pthread_mutex_t data_mutex = PTHREAD_MUTEX_INITIALIZER; pthread_cont_t data_cond = PTHREAD_COND_INITIALIZER; void *producer(void *) { pthread_mutex_lock(&data_mutex); <Produce data> <Insert data into queue;> data_avail = 1; pthread_cond_signal(&data_cond); pthread_mutex_unlock(&data_mutex); Copyright : University of Illinois CS 241 Staff 45

Example with Condition Variables void *consumer(void *) { pthread_mutex_lock(&data_mutex); while(!data_avail ) { /* sleep on condition variable*/ pthread_cond_wait(&data_cond, &data_mutex); /* woken up */ <Extract data from queue;> if (queue is empty) data_avail = 0; pthread_mutex_unlock(&data_mutex); <Consume Data> Mutex solution while(!data_avail ); /* do nothing */ No Busy Waiting! Copyright : University of Illinois CS 241 Staff 46

More Complex Example Master thread Spawns a number of concurrent slaves Waits until all of the slaves have finished to exit Tracks current number of slaves executing A mutex is associated with count and a condition variable with the mutex Copyright : University of Illinois CS 241 Staff 47

Example #include <stdio.h> #include <pthread.h> #define NO_OF_PROCS 4 typedef struct _SharedType { int count; /* number of active slaves */ pthread_mutex_t lock; /* mutex for count */ pthread_cond_t done; /* sig. by finished slave */ SharedType, *SharedType_ptr; SharedType_ptr shared_data; Copyright : University of Illinois CS 241 Staff 48

Example: Main main(int argc, char **argv) { int res; /* allocate shared data */ if ((sh_data = (SharedType *) malloc(sizeof(sharedtype))) == NULL) { exit(1); sh_data->count = 0; /* allocate mutex */ if ((res = pthread_mutex_init(&sh_data- >lock, NULL))!= 0) { exit(1); /* allocate condition var */ if ((res = pthread_cond_init(&sh_data- >done, NULL))!= 0) { exit(1); /* generate number of slaves to create */ srandom(0); /* create up to 15 slaves */ master((int) random()%16); Copyright : University of Illinois CS 241 Staff 49

Example: Main main(int argc, char **argv) { int res; /* allocate shared data */ if ((sh_data = (SharedType *) malloc(sizeof(sharedtype))) == NULL) { exit(1); sh_data->count = 0; /* allocate mutex */ exit(1); /* allocate condition var */ if ((res = pthread_mutex_t pthread_mutex_init(&sh_data- data_mutex = PTHREAD_MUTEX_INITIALIZER; >lock, NULL))!= 0) { if ((res = pthread_cond_init(&sh_datapthread_cont_t >done, NULL)) data_cond!= 0) { = PTHREAD_COND_INITIALIZER; exit(1); /* generate number of slaves to create */ srandom(0); /* create up to 15 slaves */ master((int) random()%16); Copyright : University of Illinois CS 241 Staff 50

Example: Master master(int nslaves) { int i; pthread_t id; for (i = 1; i <= nslaves; i += 1) { pthread_mutex_lock(&sh_data- >lock); /* start slave and detach */ shared_data->count += 1; pthread_create(&id, NULL, (void* (*)(void *))slave, (void *)sh_data); pthread_mutex_unlock(&sh_data- >lock); pthread_mutex_lock(&sh_data- >lock); while (sh_data->count!= 0) pthread_cond_wait(&sh_data- >done, &sh_data->lock); pthread_mutex_unlock(&sh_data- >lock); printf("all %d slaves have finished.\n", nslaves); pthread_exit(0); Copyright : University of Illinois CS 241 Staff 51

Example: Slave void slave(void *shared) { int i, n; sh_data = shared; printf( Slave.\n", n); n = random() % 1000; for (i = 0; i < n; i+= 1) Sleep(10); /* mutex for shared data */ pthread_mutex_lock(&sh_data- >lock); /* dec number of slaves */ sh_data->count -= 1; /* done running */ printf("slave finished %d cycles.\n", n); /* signal that you are done working */ pthread_cond_signal(&sh_data- >done); /* release mutex for shared data */ pthread_mutex_unlock(&sh_data- >lock); Copyright : University of Illinois CS 241 Staff 52

Semaphores vs. CVs Semaphore Integer value (>=0) Wait does not always block Signal either releases thread or inc s counter If signal releases thread, both threads continue afterwards Condition Variables No integer value Wait always blocks Signal either releases thread or is lost If signal releases thread, only one of them continue Copyright : University of Illinois CS 241 Staff 53

Next: Dining Philosophers N philosophers and N forks Philosophers eat/think Eating needs 2 forks Pick one fork at a time 2 Copyright : University of Illinois CS 241 Staff 54