Skip to content

csapp/sync_demo.c ​

配套源码,运行方法见同目录 README。返回实验总览。

c
/* A one-slot channel: condition variables guard predicates, not event counts. */
#include <assert.h>
#include <pthread.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#define ITEMS 10000

typedef struct {
    pthread_mutex_t lock;
    pthread_cond_t readable, writable;
    bool full;
    int item;
    long total;
} Channel;

static void checked(int result) { if (result != 0) { fprintf(stderr, "pthread error %d\n", result); abort(); } }
static void *producer(void *argument) {
    Channel *c = argument;
    for (int i = 1; i <= ITEMS; ++i) {
        checked(pthread_mutex_lock(&c->lock));
        while (c->full) checked(pthread_cond_wait(&c->writable, &c->lock));
        c->item = i;
        c->full = true;
        checked(pthread_cond_signal(&c->readable));
        checked(pthread_mutex_unlock(&c->lock));
    }
    return NULL;
}
static void *consumer(void *argument) {
    Channel *c = argument;
    for (int i = 1; i <= ITEMS; ++i) {
        checked(pthread_mutex_lock(&c->lock));
        while (!c->full) checked(pthread_cond_wait(&c->readable, &c->lock));
        assert(c->item == i);
        c->total += c->item;
        c->full = false;
        checked(pthread_cond_signal(&c->writable));
        checked(pthread_mutex_unlock(&c->lock));
    }
    return NULL;
}
int main(void) {
    Channel channel = {PTHREAD_MUTEX_INITIALIZER, PTHREAD_COND_INITIALIZER,
                       PTHREAD_COND_INITIALIZER, false, 0, 0};
    pthread_t p, c;
    checked(pthread_create(&p, NULL, producer, &channel));
    checked(pthread_create(&c, NULL, consumer, &channel));
    checked(pthread_join(p, NULL));
    checked(pthread_join(c, NULL));
    assert(channel.total == (long)ITEMS * (ITEMS + 1) / 2);
    printf("sync: items=%d sum=%ld\n", ITEMS, channel.total);
    checked(pthread_mutex_destroy(&channel.lock));
    checked(pthread_cond_destroy(&channel.readable));
    checked(pthread_cond_destroy(&channel.writable));
    return 0;
}