Safely sharing mutexes, barriers, and reader/writer locks between processes

Updated: April 19, 2023

You can share most synchronization objects between processes, but security can be a concern.

Most of this discussion involves mutexes, but barriers and reader/writer locks are built from mutexes, so it applies to them too.

Note: In order for processes to share a synchronization object, they must also share the memory in which it resides.

The problem with shared mutexes is that a thread in any process can claim that another thread (in any process) owns the mutex; when priority inheritance is applied, the latter's priority is boosted to that of the former. If an application needs to share a mutex between separate processes, then it must decide whether to expose itself to potential interference from unrelated processes, disable priority inheritance on the shared mutex, or force all operations on the shared mutex to enter the kernel—which they don't normally do—resulting in a performance penalty.

In QNX Neutrino 7.0.1 or later, you can configure the kernel to reject attempts to lock shared mutexes that would cause priority inheritance unless all mutex locking operations enter the kernel. This has a significant impact on the performance of shared mutexes that use the priority-inheritence protocol, but guarantees that noncooperating threads can't interfere with each other. In order to use a shared mutex in a safe manner, you must do the following:

If you specify the -s option, the kernel rejects any attempts to lock a PTHREAD_PRIO_INHERIT mutex that doesn't have PTHREAD_PROCESS_SHARED set. In this case, pthread_mutex_lock() and SyncMutexLock() give an error of EINVAL.

Similarly, if you use procnto's -s option, and you share a barrier or reader/writer lock between processes, you should use pthread_barrierattr_setpshared() or pthread_rwlockattr_setpshared() to set its process-shared attribute to PTHREAD_PROCESS_SHARED.