There is a very misleading/ambiguous statement in my linux man sem_init:
Originally Posted by
man sem_init
If pshared is nonzero, then the semaphore is shared between processes, and should be located in a region of shared memory (see shm_open(3), mmap(2), and shmget(2)). (Since a child created by fork(2) inherits its parent’s memory mappings, it can also access the semaphore.)
The bold bit is not in the POSIX standard man page:
sem_init
It is not false, but it is elliptical (missing further explication). A fork is a copy of the parents memory, addresses remain the same because they are virtual, however, the memory is not automatically shared. But if a copy of an address refers to a shared memory object, then it is the same object in both forks (and this is what the poorly worded bit in parentheses is meant to indicate).
Ie, the idea is that you use shared memory for the semaphore, and both forks receive a copy of an address that can be used to refer to it:
Code:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <semaphore.h>
#include <sys/mman.h>
#include <fcntl.h>
typedef struct {
sem_t one;
sem_t two;
} SemPair;
int main(int argc, const char *argv[]) {
int shm = shm_open("/test", O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
ftruncate(shm, sizeof(sem_t));
SemPair *sem = mmap(NULL, sizeof(sem_t), PROT_READ | PROT_WRITE, MAP_SHARED, shm, 0);
sem_init(&(sem->one), 1, 0);
sem_init(&(sem->two), 1, 0);
pid_t pid = fork();
if (!pid) {
while (1) {
sem_wait(&(sem->two));
fprintf(stderr,"Child %d\n", getpid());
sem_post(&(sem->one));
}
} else {
while (1) {
sem_post(&(sem->two));
sem_wait(&(sem->one));
fprintf(stderr,"Parent %d\n", getpid());
sleep(1); /* regulate both processes */
}
}
return 0;
}
This does a perfect:
root~/C»./a.out
Child 4880
Parent 4879
Child 4880
Parent 4879
Child 4880
Parent 4879
Child 4880
Parent 4879
[...]
However, if you change the first three lines of main() to:
Code:
SemPair *sem = malloc(sizeof(*sem));
The whole thing fails, because the semaphore is not shared between the processes.