6.6 KiB
Waitable Objects
Cross-process synchronization objects that support waiting operations with timeout capabilities.
WaitableObject Interface
All locks mentioned here implements WaitableObject. A WaitableObject offer these functions to wait while blocking the current thread:
Wait: wait until it signals. It could return false meaning the wait operation did not succeed and there is no guarantee about the status of theWaitableObject.WaitForTime: wait until it signals with a timeout. It could return false likeWait, including reaching the timeout.- IMPORTANT: it is Windows only.
Multiple Object Waiting
There are also static functions WaitAll, WaitAllForTime, WaitAny, WaitAnyForTime to wait for multiple WaitableObject at the same time.
- IMPORTANT: they are Windows only.
Platform Naming Convention
All following classes are named after Windows API. Their Linux version works exactly like Windows but with less features.
Mutex
Use Mutex for cross-process mutual exclusion.
Mutex pretty much serves the same purpose like SpinLock and CriticalSection, but it could be shared across multiple processes, meanwhile costs more OS resource. Prefer SpinLock or CriticalSection one only operates in one process.
Mutex Lifecycle
- The constructor does not actually create a mutex. You must call
CreateandOpenlater. - The
Createmethod creates a mutex.- If the name is not empty, the mutex is associated to a name, which works across different processes.
- No thread owns a mutex that is just created.
- The
Openmethod shares a created mutex with a name.
Mutex Operations
Use Create and Open methods for establishing named synchronization objects.
Use Wait, WaitForTime for blocking operations with optional timeout.
Use Release for releasing mutex and semaphore ownership.
Calling Wait will block the current thread until it owns the mutex. Calling Release release the owned mutex to other threads.
Semaphore
Use Semaphore for counting semaphore operations across processes.
Semaphore Lifecycle
- The constructor does not actually create a semaphore. You must call
CreateandOpenlater. - The
Createmethod creates a semaphore.- If the name is not empty, the semaphore is associated to a name, which works across different processes.
- No thread owns a semaphore that is just created.
- The
Openmethod shares a created semaphore with a name.
Semaphore Operations
Calling Wait will block the current thread until it owns the semaphore.
- Calling
Releaserelease the semaphore, for once or multiple times. - Unlike
Mutex, multiple threads could own the same semaphore, as long as enoughReleaseis called. And a thread doesn't need to own a semaphore to release it.
EventObject
Use EventObject for event signaling across processes.
EventObject Lifecycle
- The constructor does not actually create an event object. You must call
CreateAutoUnsignal,CreateManualUnsignalandOpenlater. - The
CreateAutoUnsignalandCreateManualUnsignalmethod creates an event object.- An auto unsignal event object means, when it is owned by a thread, it automatically unsignaled. So only one thread will be unblocked. Otherwise multiple threads waiting for this event object will be unblocked at the same time.
- If the name is not empty, the event object is associated to a name, which works across different processes.
- The
Openmethod shares a created event object with a name.
EventObject Operations
Use Signal, Unsignal for event object state management.
- Calling
Waitwill block the current thread until it is signaled. - Calling
Signalto signal an event object. - Calling
Unsignalto unsignal an event object.
Multiple Object Synchronization
Use WaitAll, WaitAllForTime, WaitAny, WaitAnyForTime for multiple object synchronization.
These static functions allow coordination with multiple waitable objects simultaneously:
WaitAll: Block until all specified objects are signaledWaitAny: Block until any one of the specified objects is signaled- Timeout versions provide time-limited waiting capabilities
Extra Content
Cross-Process Synchronization
Waitable objects provide the foundation for inter-process communication and synchronization:
- Named Objects: Objects with names can be shared across process boundaries
- Security: Named objects inherit security attributes from the creating process
- Lifetime: Objects persist as long as any process holds a reference
Performance Considerations
Waitable objects have different performance characteristics compared to in-process synchronization:
- System Overhead: Cross-process synchronization involves kernel mode switches
- Scalability: Limited by system-wide synchronization object limits
- Network Transparency: Not suitable for distributed synchronization
Error Handling
Waitable object operations can fail due to various conditions:
- Abandoned Objects: When owning process terminates unexpectedly
- Timeout Conditions: When wait operations exceed specified time limits
- System Limits: When maximum number of handles is exceeded
- Permission Issues: When processes lack appropriate access rights
Best Practices
Guidelines for effective use of waitable objects:
- Prefer In-Process: Use non-waitable primitives when cross-process sync isn't needed
- Name Carefully: Use descriptive, unique names for shared objects
- Handle Timeouts: Always handle timeout scenarios gracefully
- Resource Management: Properly close handles to avoid resource leaks
- Security Aware: Consider security implications of named objects
Platform-Specific Features
Feature availability varies by platform:
- Windows: Full support for all waitable object features
- Linux: Limited timeout support and fewer object types
- Portability: Stick to basic features for cross-platform compatibility
Integration Patterns
Common usage patterns with waitable objects:
- Process Coordination: Use
EventObjectfor startup/shutdown signaling - Resource Limiting: Use
Semaphorefor controlling access to limited resources - Mutual Exclusion: Use
Mutexfor cross-process critical sections - Complex Coordination: Combine multiple objects with
WaitAny/WaitAll
Debugging and Monitoring
Tools and techniques for troubleshooting waitable objects:
- Handle Tracking: Monitor handle counts and leaks
- Deadlock Detection: Watch for circular wait conditions
- Performance Profiling: Measure synchronization overhead
- Event Tracing: Use system tools to trace synchronization events