Why doesn't my mutex work properly in a multi-process C application? Why doesn't my mutex work properly in a multi-process C application? unix unix

Why doesn't my mutex work properly in a multi-process C application?


You should have error-checking on your semaphore calls. Use perror() to display the error if sem_wait(), sem_init() or sem_post() returns non-zero.

Secondly, you a creating more processes than you think. Your first fork() results in a parent (with producer non-zero) and a child (with producer zero). Both processes then execute the second fork(), so you now have four processes.

Thirdly, the sem_t variable must be shared between the processes, so it must be stored in a shared memory region. The easiest way to achieve this is with mmap():

sem_t *sem = mmap(NULL, sizeof *sem, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);

(Execute that prior to the sem_init() and the first fork()).

Forthly, it's not defined which process will run first, so you can't rely on the producer thread calling sem_wait() before the consumer does. Instead, initialise the semaphore to zero with sem_init(), and only call sem_wait() in the consumer - this will block the consumer. The producer executes, and calls sem_post() when it is done, which allows the consumer to proceed.

The sem_init() call should specify pshared as non-zero and value as 0, so it should look like:

if (sem_init(sem, 1, 0) != 0) {    perror("sem_init");    exit(1);}

Fifth, wait(NULL) only waits for a single child process to exit. Call it twice to wait for two child processes.


Just because you fork the producer thread first doesn't mean the OS will schedule it to run first - its quite possible that the consumer actually runs and gets the lock first.

Also, you should check the return value of sem_wait - it is posible to return from it without holding the semaphore.

It is also quite possible (as several people have noted in comments) that semaphores may simply not work across forked processes

EDIT - if you pass a non-zero value to argument 2 of sem_init(sem_t *sem, int pshared, unsigned value) when initializing posix semaphores will work across processes

EDIT - See here for a much better explanation than i could give, complete with source code to do nearly exactly what you want


Have you provided complete code in the question?

If so, you are missing semaphore initialization. You have to call either sem_init or sem_open prior to using the semaphore.

Read here.

EDIT You are specifying pshared = 0 in the sem_init call. This makes the semaphore process-local (i.e. it can be used only to synchronize threads of one process). fork creates a child process, so the semaphore does not do anything useful.

If pshared has value 0, then the semaphore is shared between the threads of a process. If pshared is non-zero, then the semaphore is shared between processes.

(the quote is from the link above)