30 条件变量
void *child(void *arg) {printf("child\n");// XXX how to indicate we are done?return NULL;}int main(int argc, char *argv[]) {printf("parent: begin\n");pthread_t c;Pthread_create(&c, NULL, child, NULL); // create child// XXX how to wait for child?printf("parent: end\n");return 0;}
Figure 30.1: A Parent Waiting For Its Child
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 childwhile (done == 0); // spinprintf("parent: end\n");return 0;}
Figure 30.2: Parent Waiting For Child: Spin-based Approach
int done = 0;pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER;pthread_cond_t c = PTHREAD_COND_INITIALIZER;void thr_exit() {Pthread_mutex_lock(&m);done = 1;Pthread_cond_signal(&c);Pthread_mutex_unlock(&m);}void *child(void *arg) {printf("child\n");thr_exit();return NULL;}void thr_join() {Pthread_mutex_lock(&m);while (done == 0)Pthread_cond_wait(&c, &m);Pthread_mutex_unlock(&m);}int main(int argc, char *argv[]) {printf("parent: begin\n");pthread_t p;Pthread_create(&p, NULL, child, NULL);thr_join();printf("parent: end\n");return 0;}
Figure 30.3: Parent Waiting For Child: Use A Condition Variable
30.1 Definition and Routines
30.2 生产者消费者(有界缓存)问题
int buffer;int count = 0; // initially, emptyvoid put(int value) {assert(count == 0);count = 1;buffer = value;}int get() {assert(count == 1);count = 0;return buffer;}
Figure 30.4: The Put And Get Routines (Version 1)
void *producer(void *arg) {int i;int loops = (int) arg;for (i = 0; i < loops; i++) {put(i);}}void *consumer(void *arg) {int i;while (1) {int tmp = get();printf("%d\n", tmp);}}
Figure 30.5: Producer/Consumer Threads (Version 1)
cond_t cond;mutex_t mutex;void *producer(void *arg) {int i;for (i = 0; i < loops; i++) {Pthread_mutex_lock(&mutex); // p1if (count == 1) // p2Pthread_cond_wait(&cond, &mutex); // p3put(i); // p4Pthread_cond_signal(&cond); // p5Pthread_mutex_unlock(&mutex); // p6}}void *consumer(void *arg) {int i;for (i = 0; i < loops; i++) {Pthread_mutex_lock(&mutex); // c1if (count == 0) // c2Pthread_cond_wait(&cond, &mutex); // c3int tmp = get(); // c4Pthread_cond_signal(&cond); // c5Pthread_mutex_unlock(&mutex); // c6printf("%d\n", tmp);}}
Figure 30.6: Producer/Consumer: Single CV And If Statement
cond_t cond;mutex_t mutex;void *producer(void *arg) {int i;for (i = 0; i < loops; i++) {Pthread_mutex_lock(&mutex); // p1while (count == 1) // p2Pthread_cond_wait(&cond, &mutex); // p3put(i); // p4Pthread_cond_signal(&cond); // p5Pthread_mutex_unlock(&mutex); // p6}}void *consumer(void *arg) {int i;for (i = 0; i < loops; i++) {Pthread_mutex_lock(&mutex); // c1while (count == 0) // c2Pthread_cond_wait(&cond, &mutex); // c3int tmp = get(); // c4Pthread_cond_signal(&cond); // c5Pthread_mutex_unlock(&mutex); // c6printf("%d\n", tmp);}}
Figure 30.8: Producer/Consumer: Single CV And While
cond_t empty, fill;mutex_t mutex;void *producer(void *arg) {int i;for (i = 0; i < loops; i++) {Pthread_mutex_lock(&mutex);while (count == 1)Pthread_cond_wait(&empty, &mutex);put(i);Pthread_cond_signal(&fill);Pthread_mutex_unlock(&mutex);}}void *consumer(void *arg) {int i;for (i = 0; i < loops; i++) {Pthread_mutex_lock(&mutex);while (count == 0)Pthread_cond_wait(&fill, &mutex);int tmp = get();Pthread_cond_signal(&empty);Pthread_mutex_unlock(&mutex);printf("%d\n", tmp);}}
Figure 30.10: Producer/Consumer: Two CVs And While
int buffer[MAX];int fill = 0;int use = 0;int count = 0;void put(int value) {buffer[fill] = value;fill = (fill + 1) % MAX;count++;}int get() {int tmp = buffer[use];use = (use + 1) % MAX;count--;return tmp;}
Figure 30.11: The Final Put And Get Routines
cond_t empty, fill;mutex_t mutex;void *producer(void *arg) {int i;for (i = 0; i < loops; i++) {Pthread_mutex_lock(&mutex); // p1while (count == MAX) // p2Pthread_cond_wait(&empty, &mutex); // p3put(i); // p4Pthread_cond_signal(&fill); // p5Pthread_mutex_unlock(&mutex); // p6}}void *consumer(void *arg) {int i;for (i = 0; i < loops; i++) {Pthread_mutex_lock(&mutex); // c1while (count == 0) // c2Pthread_cond_wait(&fill, &mutex); // c3int tmp = get(); // c4Pthread_cond_signal(&empty); // c5Pthread_mutex_unlock(&mutex); // c6printf("%d\n", tmp);}}
Figure 30.12: The Final Working Solution
30.3 Covering Conditions
// how many bytes of the heap are free?int bytesLeft = MAX_HEAP_SIZE;// need lock and condition toocond_t c;mutex_t m;void *allocate(int size) {Pthread_mutex_lock(&m);while (bytesLeft < size)Pthread_cond_wait(&c, &m);void *ptr = ...; // get mem from heapbytesLeft -= size;Pthread_mutex_unlock(&m);return ptr;}void free(void *ptr, int size) {Pthread_mutex_lock(&m);bytesLeft += size;Pthread_cond_signal(&c); // whom to signal??Pthread_mutex_unlock(&m);}
Figure 30.13: Covering Conditions: An Example
