マルチスレッドのプログラミング

「生産者 / 消費者」問題—セマフォーを使った例

例 4–14 のデータ構造は、例 4–11 の条件変数の例で使用されている構造とよく似ています。2 つのセマフォーは、いっぱいになったバッファー数と空のバッファー数をそれぞれ表します。これらのセマフォーは、バッファーが空になるまで生産者を待たせ、バッファーがいっぱいになるまで消費者を待たせます。


例 4–14 「生産者 / 消費者」問題—セマフォーを使った例

typedef struct {
    char buf[BSIZE];
    sem_t occupied;
    sem_t empty;
    int nextin;
    int nextout;
    sem_t pmut;
    sem_t cmut;
} buffer_t;

buffer_t buffer;

sem_init(&buffer.occupied, 0, 0);
sem_init(&buffer.empty,0, BSIZE);
sem_init(&buffer.pmut, 0, 1);
sem_init(&buffer.cmut, 0, 1);
buffer.nextin = buffer.nextout = 0;

もう一組の 2 進型セマフォーを mutex として使用しています。このセマフォーは、複数の生産者が複数の空バッファースロットを使用するときと、複数の消費者が複数のいっぱいになったバッファースロットを使用するときのバッファーへのアクセスを制御します。本来このような場合では mutex を使用すべきですが、セマフォーの使用例を示すために特に使用しています。


例 4–15 「生産者 / 消費者」問題—生産者

void producer(buffer_t *b, char item) {
    sem_wait(&b->empty);
    sem_wait(&b->pmut);

    b->buf[b->nextin] = item;
    b->nextin++;
    b->nextin %= BSIZE;

    sem_post(&b->pmut);
    sem_post(&b->occupied);
}


例 4–16 「生産者 / 消費者」問題—消費者

char consumer(buffer_t *b) {
    char item;

    sem_wait(&b->occupied);
   
    sem_wait(&b->cmut);

    item = b->buf[b->nextout];
    b->nextout++;
    b->nextout %= BSIZE;

    sem_post(&b->cmut);

    sem_post(&b->empty);

    return(item);
}