例 4–14 のデータ構造は、例 4–11 の条件変数の例で使用されている構造とよく似ています。2 つのセマフォーは、いっぱいになったバッファー数と空のバッファー数をそれぞれ表します。これらのセマフォーは、バッファーが空になるまで生産者を待たせ、バッファーがいっぱいになるまで消費者を待たせます。
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 を使用すべきですが、セマフォーの使用例を示すために特に使用しています。
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); }
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); }