今までに説明した 4 種類の同期プリミティブは、プロセスの境界を越えて使用するように設定できます。この境界を越えた設定を行うには、まず、その同期変数が共有メモリーセグメントに確保されるようにします。次に、USYNC_PROCESS 型に設定された適切な初期化ルーチン (init) を呼び出します。
型が USYNC_PROCESS に設定されている場合、同期変数の操作は、type が USYNC_THREAD であるときと同様に行われます。
mutex_init(&m, USYNC_PROCESS, 0); rwlock_init(&rw, USYNC_PROCESS, 0); cond_init(&cv, USYNC_PROCESS, 0); sema_init(&s, count, USYNC_PROCESS, 0);
例 6–2 に、「生産者 / 消費者」問題の生産者と消費者をそれぞれ別のプロセスで示します。メインルーチンは、子プロセスと共有されているメモリーを 0 で初期化し、それを自分のアドレス空間にマッピングします。mutex_init() と cond_init() を呼び出さなければならないのは、それらの同期変数のタイプが USYNC_PROCESS だからです。
子プロセスが 1 つ生成され、消費者の処理が実行されます。親プロセスは生産者の処理を実行します。
この例では、生産者と消費者を呼び出す各駆動ルーチンも示しています。producer_driver は、stdin から文字を読み込み、producer を呼び出します。consumer_driver は、consumer を呼び出して文字を受け取り、stdout に書き出します。
例 6–2 のデータ構造は、条件変数によるソリューションで使用したものと同じです。「片方向リンクリストの入れ子のロック」を参照してください。
main() {
int zfd;
buffer_t *buffer;
zfd = open(“/dev/zero”, O_RDWR);
buffer = (buffer_t *)mmap(NULL, sizeof(buffer_t),
PROT_READ|PROT_WRITE, MAP_SHARED, zfd, 0);
buffer->occupied = buffer->nextin = buffer->nextout = 0;
mutex_init(&buffer->lock, USYNC_PROCESS, 0);
cond_init(&buffer->less, USYNC_PROCESS, 0);
cond_init(&buffer->more, USYNC_PROCESS, 0);
if (fork() == 0)
consumer_driver(buffer);
else
producer_driver(buffer);
}
void producer_driver(buffer_t *b) {
int item;
while (1) {
item = getchar();
if (item == EOF) {
producer(b, `\0');
break;
} else
producer(b, (char)item);
}
}
void consumer_driver(buffer_t *b) {
char item;
while (1) {
if ((item = consumer(b)) == '\0')
break;
putchar(item);
}
}
子プロセスが 1 つ生成され、消費者の処理が実行されます。親プロセスは生産者の処理を実行します。