Each of the synchronization primitives can be set up to be used across process boundaries. This is done quite simply by ensuring that the synchronization variable is located in a shared memory segment and by calling the appropriate init() routine, after the primitive has been initialized with its shared attribute set as interprocess.
Example 4-17 shows the producer/consumer problem with the producer and consumer in separate processes. The main routine maps zero-filled memory (that it shares with its child process) into its address space.
A child process is created that runs the consumer. The parent runs the producer.
This example also shows the drivers for the producer and consumer. The producer_driver() simply reads characters from stdin and calls producer(). The consumer_driver() gets characters by calling consumer() and writes them to stdout.
The data structure for Example 4-17 is the same as that used for the condition variables example (see Example 4-4). Two semaphores represent the number of full and empty buffers and ensure that producers wait until there are empty buffers and that consumers wait until there are full buffers.
main() { int zfd; buffer_t *buffer; pthread_mutexattr_t mattr; pthread_condattr_t cvattr_less, cvattr_more; 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; pthread_mutex_attr_init(&mattr); pthread_mutexattr_setpshared(&mattr, PTHREAD_PROCESS_SHARED); pthread_mutex_init(&buffer->lock, &mattr); pthread_condattr_init(&cvattr_less); pthread_condattr_setpshared(&cvattr_less, PTHREAD_PROCESS_SHARED); pthread_cond_init(&buffer->less, &cvattr_less); pthread_condattr_init(&cvattr_more); pthread_condattr_setpshared(&cvattr_more, PTHREAD_PROCESS_SHARED); pthread_cond_init(&buffer->more, &cvattr_more); 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); } }