// // NSThreadWaiter.m // NSThreadExtension // // Created by Jonathan Lung on 10/03/07. // Copyright 2007 __MyCompanyName__. All rights reserved. // http://www.cs.toronto.edu/~lungj #import "NSThreadWaiter.h" static NSConditionLock* threadCountLock; // A class for containing SELs @interface SelectorContainer : NSObject { SEL selector; } @end @implementation SelectorContainer -(id) initWithSelector:(SEL) aSelector { self = [super init]; selector = aSelector; return self; } -(SEL) getSelector { return selector; } @end #pragma mark - @implementation NSThread (Waiting) +(void) initialize { [super initialize]; threadCountLock = [[NSConditionLock alloc] initWithCondition:0]; } +(void)detachNewCountedThreadSelector:(SEL)aSelector toTarget:(id)aTarget withObject:(id)anArgument { // Wrap the parameters to this method. SelectorContainer* selContainer = [[SelectorContainer alloc] initWithSelector:aSelector]; // Note that if anArgument is nil, an NSArray of length 2 is created. NSArray* params = [[NSArray alloc] initWithObjects:selContainer, aTarget, anArgument, nil]; // NSArray has already retained selfContainer. [selContainer release]; // Increment the thread count in anticipation of the started thread. [threadCountLock lock]; [threadCountLock unlockWithCondition:[threadCountLock condition] + 1]; // Detach the thread [NSThread detachNewThreadSelector:@selector(runSelectedMethod:) toTarget:self withObject:params]; } // This method calls the selector of the object passed to // detachNewCountedThreadSelector:toTarget:withObject:. +(void)runSelectedMethod:(NSArray*)params { SEL aSelector = [(SelectorContainer *)[params objectAtIndex:0] getSelector]; id aTarget = [params objectAtIndex:1]; id anArgument = nil; if ([params count] > 2) { // If [params count] > 2, the original anArgument wasn't nil. anArgument = [params objectAtIndex:2]; } [aTarget performSelector:aSelector withObject:anArgument]; // Normally shouldn't do this... we don't have ownership. // But saves using an autorelease pool and avoids some other problems. [params release]; // Decrement the thread count since this thread is done. [threadCountLock lock]; [threadCountLock unlockWithCondition:[threadCountLock condition] - 1]; } +(void)sleepUntilThreadsNumber:(int) numberOfThreads { // Block until number of threads is equal to numberOfThreads. // Is not guaranteed [threadCountLock lockWhenCondition:numberOfThreads]; [threadCountLock unlock]; } +(int)detachedThreads { // Lock the thread count before reading and returning the value. [threadCountLock lock]; int threads = [threadCountLock condition]; [threadCountLock unlock]; return threads; } @end