I am try to make one function wait for another, and I would like to use NSCondionLock in order to accomplish this. I am not asking for help, but really hoping someone could show me a decent tutorial or example to explain NSConditionLock, or possibly suggest a better method.
4 Answers
EDIT: as @Bonshington commented, this answer refers to NSCondition
(as opposed to NSConditionLock
):
- (void) method1 {
[myCondition lock];
while (!someCheckIsTrue)
[myCondition wait];
// Do something.
[myCondition unlock];
}
- (void) method2 {
[myCondition lock];
// Do something.
someCheckIsTrue = YES;
[myCondition signal];
[myCondition unlock];
}
The someCheckIsTrue
can be anything, it could be a simple BOOL variable or even something like [myArray count] == 0 && color == kColorRed
, it doesn't matter. It only matters that in one method you check for a condition while you have the lock and in another method you make changes that can make the condition become true also while having the lock. The magic is the wait
and signal
part: the wait
actually unlocks the lock and reacquires it after some other thread called signal
.

- 90,870
- 19
- 190
- 224
-
How do I declare it? Is it just NSConditionLock *lock = [[NSConditionLock alloc] init] ? And should I declare it in whatever method calls the two function that need to be synchronized? Sorry if I did not format my comment properly, this is my first time really posting. – gurooj Jul 15 '11 at 08:26
-
2You should declare it as an instance variable in your class, `NSConditionLock *lock;`. You then initialize it in your `init` with `lock = [[NSConditionLock alloc] init];`, that's it. Also, in `dealloc`, you simply release it: `[lock release];`. Or if the methods are in different classes, then you need to define the lock somewhere where both methods have access to. – DarkDust Jul 15 '11 at 09:15
-
So in this case, is the method 1 waiting for the second method? Or vice versa? Because when I implemented this, my program gets stuck on [MyConditionLock wait] – gurooj Jul 16 '11 at 00:35
-
1@gurooj: First of all, the methods must run on different threads. So they may not call each other, otherwise you'd have a deadlock. Now, first `method1` needs to run and hit `wait`, then `method2` will wake it up with `signal`. – DarkDust Jul 16 '11 at 09:10
-
Ok. Thank you for the help. I ended up using performSelectorOnMainThread and performSelectorInBackground to accomplish the task anyways. The waitUntilDone parameter allowed me to skip all the condition code. – gurooj Jul 18 '11 at 07:52
-
14NSConditionLock doesn't have wait, signal. its NSCondition – Bonshington Oct 20 '11 at 04:09
-
Shouldn't someCheckIsTrue be set to YES before the sensitive code is executed? – Sabobin Jun 06 '13 at 12:18
-
As long as the variable is only every read or set between `[myCondition lock];` and `[myCondition unlock];` it doesn't matter when exactly you set the variable. As long as you only access it between `lock` and `unlock` you can consider these blocks to be atomic. That's the whole point of mutexes and locks. – DarkDust Jun 06 '13 at 15:38
-
but what if multiple threads are stuck on "while (!someCheckIsTrue)" and then the signal happens? Can they 2 threads at the same time pass that condition before the bool is set to false again? – MobileMon Dec 01 '14 at 15:28
-
1@MobileMon: No. Quote from the [documentation of `signal`](https://developer.apple.com/library/mac/documentation/Cocoa/Reference/NSCondition_class/index.html#//apple_ref/occ/instm/NSCondition/signal): _You use this method to wake up **one** thread that is waiting on the condition._ (emphasize mine) – DarkDust Dec 01 '14 at 15:44
For those that want a sample test class here I post what I did to play around and understand how NSCondition works.
// --- MyTestClass.h File --- //
@interface MyTestClass
- (void)startTest;
@end
// --- MyTestClass.m File --- //
@implementation MyTestClass
{
NSCondition *_myCondition;
BOOL _someCheckIsTrue;
}
- (id)init
{
self = [super init];
if (self)
{
_someCheckIsTrue = NO;
_myCondition = [[NSCondition alloc] init];
}
return self;
}
#pragma mark Public Methods
- (void)startTest
{
[self performSelectorInBackground:@selector(_method1) withObject:nil];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
sleep(5);
[self performSelectorInBackground:@selector(_method2) withObject:nil];
});
}
#pragma mark Private Methods
- (void)_method1
{
NSLog(@"STARTING METHOD 1");
NSLog(@"WILL LOCK METHOD 1");
[_myCondition lock];
NSLog(@"DID LOCK METHOD 1");
while (!_someCheckIsTrue)
{
NSLog(@"WILL WAIT METHOD 1");
[_myCondition wait];
NSLog(@"DID WAIT METHOD 1");
}
NSLog(@"WILL UNLOCK METHOD 1");
[_myCondition unlock];
NSLog(@"DID UNLOCK METHOD 1");
NSLog(@"ENDING METHOD 1");
}
- (void)_method2
{
NSLog(@"STARTING METHOD 2");
NSLog(@"WILL LOCK METHOD 2");
[_myCondition lock];
NSLog(@"DID LOCK METHOD 2");
_someCheckIsTrue = YES;
NSLog(@"WILL SIGNAL METHOD 2");
[_myCondition signal];
NSLog(@"DID SIGNAL METHOD 2");
NSLog(@"WILL UNLOCK METHOD 2");
[_myCondition unlock];
NSLog(@"DID UNLOCK METHOD 2");
}
@end
// --- Output --- //
/*
2012-11-14 11:01:21.416 MyApp[8375:3907] STARTING METHOD 1
2012-11-14 11:01:21.418 MyApp[8375:3907] WILL LOCK METHOD 1
2012-11-14 11:01:21.419 MyApp[8375:3907] DID LOCK METHOD 1
2012-11-14 11:01:21.421 MyApp[8375:3907] WILL WAIT METHOD 1
2012-11-14 11:01:26.418 MyApp[8375:4807] STARTING METHOD 2
2012-11-14 11:01:26.419 MyApp[8375:4807] WILL LOCK METHOD 2
2012-11-14 11:01:26.419 MyApp[8375:4807] DID LOCK METHOD 2
2012-11-14 11:01:26.420 MyApp[8375:4807] WILL SIGNAL METHOD 2
2012-11-14 11:01:26.420 MyApp[8375:4807] DID SIGNAL METHOD 2
2012-11-14 11:01:26.421 MyApp[8375:4807] WILL UNLOCK METHOD 2
2012-11-14 11:01:26.421 MyApp[8375:3907] DID WAIT METHOD 1
2012-11-14 11:01:26.421 MyApp[8375:4807] DID UNLOCK METHOD 2
2012-11-14 11:01:26.422 MyApp[8375:3907] WILL UNLOCK METHOD 1
2012-11-14 11:01:26.423 MyApp[8375:3907] DID UNLOCK METHOD 1
2012-11-14 11:01:26.423 MyApp[8375:3907] ENDING METHOD 1
*/

- 2,097
- 2
- 21
- 25
-
Thank you but your example doesn't illustrate why using `while (!_someCheckIsTrue)` instead of `if (!_someCheckIsTrue)`. – Cœur Apr 14 '20 at 10:00
Swift 5 version of @vilanovi answer from Playground:
let myCondition = NSCondition()
var someCheckIsTrue = false
func method1() {
print("STARTING METHOD 1")
print("WILL LOCK METHOD 1")
myCondition.lock()
print("DID LOCK METHOD 1")
while (!someCheckIsTrue) {
print("WILL WAIT METHOD 1")
myCondition.wait()
print("DID WAIT METHOD 1")
}
print("WILL UNLOCK METHOD 1")
myCondition.unlock()
print("DID UNLOCK METHOD 1")
print("ENDING METHOD 1")
}
func method2() {
print("STARTING METHOD 2")
print("WILL LOCK METHOD 2")
myCondition.lock()
print("DID LOCK METHOD 2")
someCheckIsTrue = true
print("WILL SIGNAL METHOD 2")
myCondition.signal()
print("DID SIGNAL METHOD 2")
print("WILL UNLOCK METHOD 2")
myCondition.unlock()
print("DID UNLOCK METHOD 2")
print("ENDING METHOD 2")
}
DispatchQueue.global().async {
method1()
}
DispatchQueue.global().asyncAfter(deadline: DispatchTime.now() + 0.5) {
method2()
}

- 1,999
- 2
- 21
- 28
NSConditionLock
example program.
#import <Foundation/Foundation.h>
#define IDLE 0
#define START 1
#define TASK_1_FINISHED 2
#define TASK_2_FINISHED 3
#define CLEANUP_FINISHED 4
#define SHARED_DATA_LENGTH 1024 * 1024 * 1024
int main(int argc, const char * argv[]) {
@autoreleasepool {
NSConditionLock *lock = [[NSConditionLock alloc] initWithCondition:IDLE];
char *shared_data = calloc(SHARED_DATA_LENGTH, sizeof(char));
[NSThread detachNewThreadWithBlock:^{
[lock lockWhenCondition:START];
NSLog(@"[Thread-1]: Task 1 started...");
for (size_t i = 0; i < SHARED_DATA_LENGTH; i++) {
shared_data[i] = 0x00;
}
[lock unlockWithCondition:TASK_1_FINISHED];
}];
[NSThread detachNewThreadWithBlock:^{
[lock lockWhenCondition:TASK_1_FINISHED];
NSLog(@"[Thread-2]: Task 2 started...");
for (size_t i = 0; i < SHARED_DATA_LENGTH; i++) {
char c = shared_data[i];
shared_data[i] = ~c;
}
[lock unlockWithCondition:TASK_2_FINISHED];
}];
[NSThread detachNewThreadWithBlock:^{
[lock lockWhenCondition:TASK_2_FINISHED];
NSLog(@"[Thread-3]: Cleaning up...");
free(shared_data);
[lock unlockWithCondition:CLEANUP_FINISHED];
}];
NSLog(@"[Thread-main]: Threads set up. Waiting for 2 task to finish");
[lock unlockWithCondition:START];
[lock lockWhenCondition:CLEANUP_FINISHED];
NSLog(@"[Thread-main]: Completed");
}
return 0;
}

- 654
- 1
- 10
- 22