So far, we have been using the default settings for our synchronization tools, often initializing them with simple macros like PTHREAD_MUTEX_INITIALIZER.
This section introduces Attributes, which allow us to customize behavior. The most critical attribute—and the main reason this section exists in an IPC book—is the ability to share mutexes between different processes, not just different threads.
1. The Goal: Synchronization Across Processes
By default, mutexes and condition variables are process-private. They only work for threads inside the same process.
- The Problem: If you fork a process, or unrelated processes map a region of Shared Memory (which we will cover in Part 4), they cannot use default mutexes to coordinate.
- The Solution: We must explicitly tell the system that these synchronization objects will be shared by setting the
PTHREAD_PROCESS_SHAREDattribute.
2. The Setup Sequence
To change an attribute, you cannot use the static assignment (e.g., = PTHREAD...). You must use a specific sequence of function calls.
The “Boilerplate” Pattern:
- Initialize an attribute object.
- Set the specific flags you want on that object.
- Initialize the mutex/cond using that attribute object.
- Destroy the attribute object (you don’t need it anymore).
3. Annotated Code Example
Here is how you initialize a mutex that resides in shared memory so multiple processes can use it safely:
// 1. Declare the attribute and the mutex pointer
pthread_mutexattr_t mattr;
pthread_mutex_t *mptr;
// Assume 'mptr' points to a region of Shared Memory we allocated...
// 2. Initialize the attribute
Pthread_mutexattr_init(&mattr);
// 3. KEY STEP: Set the "Process Shared" attribute
// This tells the kernel: "Expect other processes to touch this lock."
Pthread_mutexattr_setpshared(&mattr, PTHREAD_PROCESS_SHARED);
// 4. Initialize the mutex using these attributes
Pthread_mutex_init(mptr, &mattr);
// 5. Clean up the attribute object (not needed after init)
Pthread_mutexattr_destroy(&mattr);4. The Critical Danger: Process Termination
Stevens places a heavy emphasis on a major downside of using Mutexes/Condition Variables for Inter-process Communication: Lack of Robustness.
- The Scenario: Process A locks a mutex in shared memory and then crashes (segfault, kill signal, etc.) before unlocking it.
- The Result: The mutex remains locked forever.
- The Consequence: Process B (and C, D…) will eventually try to acquire that lock and will hang indefinitely.
Unlike Record Locking (Chapter 9) or System V Semaphores (Chapter 11), the kernel does not automatically clean up mutexes when a process dies. If you use mutexes across processes, you must design your application carefully to handle crashes (or accept the risk).