Using Mutexes/Semaphores with Processes

Is it possible to use mutex in multiprocessing case on Linux/UNIX ?

Mutual exclusion locks (mutexes) prevent multiple threads
from simultaneously executing critical sections of code that
access shared data (that is, mutexes are used to serialize
the execution of threads). All mutexes must be global. A
successful call for a mutex lock by way of mutex_lock()
will cause another thread that is also trying to lock the
same mutex to block until the owner thread unlocks it by way
of mutex_unlock(). Threads within the same process or
within other processes can share mutexes.

Mutexes can synchronize threads within the same process or
in other processes. Mutexes can be used to synchronize
threads between processes if the mutexes are allocated in
writable memory and shared among the cooperating processes
(see mmap(2)), and have been initialized for this task.

Initialization

Mutexes are either intra-process or inter-process, depending
upon the argument passed implicitly or explicitly to the
initialization of that mutex. A statically allocated mutex
does not need to be explicitly initialized; by default, a
statically allocated mutex is initialized with all zeros
and its scope is set to be within the calling process.

For inter-process synchronization, a mutex needs to be allo-
cated in memory shared between these processes. Since the
memory for such a mutex must be allocated dynamically, the
mutex needs to be explicitly initialized using mutex_init().

How to use mutexes in a shared memory forked process?

Since you don't have any mutexes, there's nothing to stop two processes from trying to increment the counter simultaneously, and since increment of an int is generally not atomic, this is an immediate race condition. Over and above the increment race, the routine increments and then reads the value, which is also not atomic, so subject to races.

In order to avoid races, you need some sort of mutex. You could use a semaphore, or you might be able to use a pthread mutex in shared memory (if you have pthreads available). Alternately you may be able use file locks, or you could write your own atomic assembly routines and call them. If you're using C11, you could even use the stuff in stdatomic.h. Lots of possible choices.

edit

You can wrap a mutex around the racing operations to avoid the race condition at the end of your increment function:

    struct sembuf sem_ops = { 0, -1, SEM_UNDO };
semop(semid, &sem_ops, 1);
*shm++;
rv = *shm;
sem_ops.sem_op = 1;
semop(semid, &sem_ops, 1);
return rv;
}

Generally, you'll just attach the shared memory once in each process (and create it once in one process), and then just use it, without repeatedly attaching and detaching it. Similarly, you'll create and initialize your mutexes once, and then use them.

Semaphores and Mutex for Thread and Process Synchronization

The answer to both questions is yes. You can create both mutexes and semaphores as either process-shared or not. So you can use them as interprocess or interthread synchronization objects, but you have to specify which when you create them.

Of course, you must create the synchronization object in memory that is shared by all contexts that wish to access it. With threads, that's trivial since they share a view of memory. With processes, you have to create the synchronization object in shared memory specifically.

Difference between a mutex and semaphore - intra process and inter process

A semaphore is a synchronization mechanism build around an integer value. Locking a semaphore (usually called "waiting on semaphore") decreases the value unless it's 0. In that case the thread is stopped until the semaphore value is greater than 0, so it can be properly decreased. Unlocking the semaphore (usually called "posting" or "signalling") increases the value by 1, unconditionally.

Usually when creating a semaphore you need to assign it a starting value. If you set a value bigger than 1, you can have multiple threads enter code "protected" by a semaphore.

Now, a mutex is a binary synchronization primitive. Conceptually it can be compared to a semaphore with an initial value of 1. Only a single thread can enter code protected by a mutex.

I don't know the Windows world, but on Unix semaphore is a OS construct and it can be used to synchronize multiple processes. Pthread mutexes are usually used for coordinating threads within a single process, but there are tricks that allow using mutexes for inter-process synchronization (shared memory block and special ways to create a mutex).

Using pthread mutex shared between processes correctly

Am I right that the pthread_mutex_init doesn't provide any safe approach to initialize the pthread_mutex_t simultaneously from different processes?

Correct. It is up to you to ensure that only one process calls pthread_mutex_init() on the mutex, and that no process tries to operate on the mutex until that call has successfully returned.

For example, with POSIX shm_open() shared memory regions, you can have the processes try to open the region with the O_CREAT and O_EXCL flags, so that exactly one process will succeed in creating it. This process is then responsible for resizing the shared memory region and initialising the mutex with pthread_mutex_init(). The other processes must then wait for some kind of notification from the initialising process before opening the shared memory region - eg you could have the processes block opening a FIFO O_RDONLY, and have the initialising process notify them by opening the FIFO O_WRONLY (which will cause the open to succeed).

Usually, a shared memory segment will not be the only communication channel between the processes. Typically you would bootstrap the communication through a UNIX domain socket and negotiate the setup of the shared memory region over it, probably even passing the shared memory region file descriptor through the socket with a SCM_RIGHTS message. The shared memory region would then be used to accelerate the performance-sensitive IPC.



Related Topics



Leave a reply



Submit