- Inherits from:
- NSObject
- Conforms to:
- NSLocking
- NSObject (NSObject)
Declared in:
- Foundation/NSLock.h
The NSConditionLock class defines objects whose locks can be associated with specific, user-defined conditions. Using an NSConditionLock object, you can ensure that a thread can acquire a lock only if a certain condition is met. Once it has acquired the lock and executed the critical section of code, the thread can relinquish the lock and set the associated condition to something new. The conditions themselves are arbitrary: You define them as needed for your application.
Typically, you use an NSConditionLock object when threads in your application need to execute in a particular order, such as when one thread produces data that another consumes. While the producer is executing, the consumer sleeps waiting to acquire a lock that's conditional upon the producer's completion of its operation. An application can have multiple NSConditionLock objects, each protecting different sections of code. It's safest to create all of the locks before the application becomes multi-threaded, to avoid race conditions. If you want to create additional locks after the application becomes multi-threaded, you should create the new lock inside a critical code section that is itself protected by an existing lock.
The locking and unlocking methods that NSConditionLock objects respond to can be used in any combination. For example, you can pair a lock message with unlockWithCondition:, or a lockWhenCondition: message with unlock.
The following example shows how the producer-consumer problem might be handled using condition locks. Imagine that an application contains a queue of data. A producer thread adds data to the queue, and consumer threads extract data from the queue.
The producer need not wait for a condition, but must wait for the lock to be made available so it can safely add data to the queue. For example, a producer could use a lock this way:
id condLock = [[NSConditionLock alloc] initWithCondition:NO_DATA]; [condLock lock]; /* Add data to the queue. */ [condLock unlockWithCondition:HAS_DATA];
Note that in acquiring the lock, the producer sets its condition
to the user-defined value NO_DATA
. After
adding data to the queue, the producer relinquishes the lock, setting
its condition to HAS_DATA
.
A consumer thread waits until there's data available and all other threads are out of locked critical sections. In the following code, the consumer sleeps until there is data in the queue and a lock can be acquired:
[condLock lockWhenCondition:HAS_DATA]; /* Remove data from the queue. */ [condLock unlockWithCondition:(isEmpty ? NO_DATA : HAS_DATA)];
The consumer removes some data from the queue and then relinquishes
the lock, setting its value to NO_DATA
or HAS_DATA
,
depending on whether the queue is now empty.
The NSConditionLock, NSLock, and NSRecursiveLock classes all adopt the NSLocking protocol with various features and performance characteristics; see the other class descriptions for more information.
NSLocking
- - lock
- - unlock
- Initializing an NSConditionLock
- - initWithCondition:
- Returning the condition
- - condition
- Acquiring and releasing a lock
- - lockBeforeDate:
- - lockWhenCondition:
- - lockWhenCondition:beforeDate:
- - tryLock
- - tryLockWhenCondition:
- - unlockWithCondition:
- (int)condition
- (id)initWithCondition:(int)condition
- (BOOL)lockBeforeDate:(NSDate
*)limit
The condition associated with the receiver isn't taken into account in this operation.
See Also: - lockWhenCondition:beforeDate:
- (void)lockWhenCondition:(int)condition
See Also: - lockWhenCondition:beforeDate:, - unlockWithCondition:
- (BOOL)lockWhenCondition:(int)condition
beforeDate:(NSDate *)limit
See Also: - lockBeforeDate:, - lockWhenCondition:
- (BOOL)tryLock
See Also: - tryLockWhenCondition:
- (BOOL)tryLockWhenCondition:(int)condition
See Also: - tryLock
- (void)unlockWithCondition:(int)condition
See Also: - lockWhenCondition: