How to join threads in Objective C without using delegates/callback?
Is there a clean way of joining threads in Objective C much l开发者_运维技巧ike "Thread.join" in Java? I found the method performSelector:onThread:withObject:waitUntilDone: but the limitation of this is I can't call the "blocking" on a different line because I want to do something like this:
[dispatch Thread A];
[process something on main thread];
[wait for Thread A to finish before proceeding];
Thank you in advance.
I'm not aware of any Cocoa API to do this, but it wouldn't be too difficult to do with NSThread
, pretty easy to do with a lock, and even easier to do with Grand Central Dispatch.
NSThread
NSThread * otherThread = [[NSThread alloc] initWithTarget:self selector:@selector(methodToPerformInBackground:) object:aParameter];
[otherThread start];
//do some stuff
while ([otherThread isFinished] == NO) {
usleep(1000);
}
[otherThread release];
NSLock
NSLock * lock = [[NSLock alloc] init];
//initiate the background task, which should immediately lock the lock and unlock when done
//do some stuff
[lock lock]; //this will pause until the background stuff unlocks
[lock unlock];
[lock release];
Grand Central Dispatch
dispatch_group_t myGroup = dispatch_group_create();
dispatch_group_async(myGroup, dispatch_get_global_queue(), ^{
//stuff to do in the background
});
//do some stuff
dispatch_group_wait(myGroup, DISPATCH_TIME_FOREVER);
dispatch_release(myGroup);
NSConditionLock is the answer to my question, Sorry Dave DeLong, but I cannot use:
"while ([otherThread isFinished] == NO) " -- because I need fast continuous processing and cannot use sleep.
NSLock -- because as you said it "initiate the background task, which should immediately lock the lock and unlock when done", this is not a solution because I tried it and we are not sure if the subthread will execute last before the lock-unlock-release on main thread, I ended up getting random errors.
Grand Central Dispatch --because it's only available in IOS4 and Snow Leopard 10.6, I'm using a lower version.
But your answer gave me the idea and thank you very much for it, so I just "upped" you.
I ended up doing this:
#define T_START 0
#define T_FINISHED 1
-(void) updateVerticalScopeBackground: (id) aParam {
[lockForThread lock];
NSAutoreleasePool *pool = [NSAutoreleasePool new];
//do something
[pool release];
[lockForThread unlockWithCondition:T_FINISHED];
}
-(void) sumFunc {
lockForThread = [[NSConditionLock alloc]
initWithCondition: T_START];
NSThread* updateVerticalScope = [[NSThread alloc] initWithTarget:self selector:@selector(updateVerticalScopeBackground:) object:nil];
[updateVerticalScope start];
//do some processing
[lockForThread lockWhenCondition:T_FINISHED];
[lockForThread unlockWithCondition:T_FINISHED];
[lockForThread release];
}
You could use NSCondition signal/wait.
Could you use a lock to do this? In other words something like this (pseudocode)
- create an object to lock on, visible to both threads
- dispatch thread A; thread A immediately takes the lock and keeps it for its duration
- process something on main thread
- main thread attempts to take the lock (this will block until Thread A releases it)
- after acquiring the lock, main thread releases it and continues on
You never want your main thread to be blocked waiting for another thread. At least you don't in any application with a user interface because, if the main thread is blocked, your application is frozen.
It would be far better for the main thread to start the background thread, do the other stuff it needs to do and then return to the run loop. The background thread would notify the main thread of completion by sending -performSelectorOnMainThread:waitUntilDone:
精彩评论