Go to main content

Multithreaded Programming Guide

Exit Print View

Updated: November 2020
 
 

Synchronizing Across Process Boundaries

Each of the synchronization primitives can be set up to be used across process boundaries. This cross-boundary setup is done by ensuring that the synchronization variable is located in a shared memory segment and by calling the appropriate init routine with type set to USYNC_PROCESS.

If type is set to USYNC_PROCESS, then the operations on the synchronization variables work just as the variables do when type is 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);

Producer and Consumer Problem

Example 29, Producer and Consumer Problem Using USYNC_PROCESS shows the producer and consumer problem with the producer and consumer in separate processes. The main routine maps zero-filled memory that main shares with its child process, into its address space. Note that mutex_init() and cond_init() must be called because the type of the synchronization variables is USYNC_PROCESS.

A child process is created to run the consumer. The parent runs the producer.

This example also shows the drivers for the producer and consumer. The producer_driver reads characters from stdin and calls the producer. The consumer_driver gets characters by calling the consumer and writes them to stdout.

The data structure for Example 29, Producer and Consumer Problem Using USYNC_PROCESS is the same as that used for the solution with condition variables. See Examples of Using Nested Locking With a Singly-Linked List.

Example 29  Producer and Consumer Problem Using USYNC_PROCESS
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);
    }
}

A child process is created to run the consumer. The parent runs the producer.