mirror of
https://github.com/gnustep/libs-base.git
synced 2025-04-22 16:33:29 +00:00
re-introduce thread pool
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@32442 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
parent
11c393b2dc
commit
6d21d67c23
3 changed files with 106 additions and 10 deletions
|
@ -1,9 +1,13 @@
|
|||
2011-03-03 Richard Frith-Macdonald <rfm@gnu.org>
|
||||
|
||||
* Source/NSOperation.m: re-introduce per-queue thread pool.
|
||||
|
||||
2011-03-03 Richard Frith-Macdonald <rfm@gnu.org>
|
||||
|
||||
* Source/NSOperation.m: reorganise and simplify code, removing the
|
||||
pool of threads for handling operations (need to re-add this at a
|
||||
later point, but probably as a separate class) ... implement
|
||||
support for 'concurrent' operations (ones which mange their own
|
||||
support for 'concurrent' operations (ones which manage their own
|
||||
executions rather than running in a thread provided by the queue.
|
||||
|
||||
2011-03-03 Richard Frith-Macdonald <rfm@gnu.org>
|
||||
|
|
|
@ -45,11 +45,14 @@
|
|||
|
||||
#define GS_NSOperationQueue_IVARS \
|
||||
NSRecursiveLock *lock; \
|
||||
NSConditionLock *cond; \
|
||||
NSMutableArray *operations; \
|
||||
NSMutableArray *waiting; \
|
||||
NSMutableArray *starting; \
|
||||
NSString *name; \
|
||||
BOOL suspended; \
|
||||
NSInteger executing; \
|
||||
NSInteger threadCount; \
|
||||
NSInteger count;
|
||||
|
||||
#import "Foundation/NSOperation.h"
|
||||
|
@ -66,6 +69,10 @@
|
|||
#include "GSInternal.h"
|
||||
GS_PRIVATE_INTERNAL(NSOperation)
|
||||
|
||||
/* The pool of threads for 'non-concurrent' operations in a queue.
|
||||
*/
|
||||
#define POOL 8
|
||||
|
||||
static NSArray *empty = nil;
|
||||
|
||||
@interface NSOperation (Private)
|
||||
|
@ -539,6 +546,7 @@ GS_PRIVATE_INTERNAL(NSOperationQueue)
|
|||
@interface NSOperationQueue (Private)
|
||||
+ (void) _mainQueue;
|
||||
- (void) _execute;
|
||||
- (void) _thread;
|
||||
- (void) observeValueForKeyPath: (NSString *)keyPath
|
||||
ofObject: (id)object
|
||||
change: (NSDictionary *)change
|
||||
|
@ -720,8 +728,10 @@ static NSOperationQueue *mainQueue = nil;
|
|||
- (void) dealloc
|
||||
{
|
||||
[internal->operations release];
|
||||
[internal->starting release];
|
||||
[internal->waiting release];
|
||||
[internal->name release];
|
||||
[internal->cond release];
|
||||
[internal->lock release];
|
||||
GS_DESTROY_INTERNAL(NSOperationQueue);
|
||||
[super dealloc];
|
||||
|
@ -735,8 +745,10 @@ static NSOperationQueue *mainQueue = nil;
|
|||
internal->suspended = NO;
|
||||
internal->count = NSOperationQueueDefaultMaxConcurrentOperationCount;
|
||||
internal->operations = [NSMutableArray new];
|
||||
internal->starting = [NSMutableArray new];
|
||||
internal->waiting = [NSMutableArray new];
|
||||
internal->lock = [NSRecursiveLock new];
|
||||
internal->cond = [[NSConditionLock alloc] initWithCondition: 0];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
@ -901,6 +913,75 @@ static NSOperationQueue *mainQueue = nil;
|
|||
[self _execute];
|
||||
}
|
||||
|
||||
- (void) _thread
|
||||
{
|
||||
NSAutoreleasePool *pool = [NSAutoreleasePool new];
|
||||
|
||||
for (;;)
|
||||
{
|
||||
NSOperation *op;
|
||||
NSDate *when;
|
||||
BOOL found;
|
||||
|
||||
when = [[NSDate alloc] initWithTimeIntervalSinceNow: 5.0];
|
||||
found = [internal->cond lockWhenCondition: 1 beforeDate: when];
|
||||
[when release];
|
||||
if (NO == found)
|
||||
{
|
||||
break; // Idle for 5 seconds ... exit thread.
|
||||
}
|
||||
|
||||
if ([internal->starting count] > 0)
|
||||
{
|
||||
op = [internal->starting objectAtIndex: 0];
|
||||
[internal->starting removeObjectAtIndex: 0];
|
||||
}
|
||||
else
|
||||
{
|
||||
op = nil;
|
||||
}
|
||||
|
||||
if ([internal->starting count] > 0)
|
||||
{
|
||||
// Signal any other idle threads,
|
||||
[internal->cond unlockWithCondition: 1];
|
||||
}
|
||||
else
|
||||
{
|
||||
// There are no more operations starting.
|
||||
[internal->cond unlockWithCondition: 0];
|
||||
}
|
||||
|
||||
if (nil != op)
|
||||
{
|
||||
NS_DURING
|
||||
{
|
||||
NSAutoreleasePool *opPool = [NSAutoreleasePool new];
|
||||
|
||||
if (NO == [op isCancelled])
|
||||
{
|
||||
[NSThread setThreadPriority: [op threadPriority]];
|
||||
[op main];
|
||||
}
|
||||
[opPool release];
|
||||
}
|
||||
NS_HANDLER
|
||||
{
|
||||
NSLog(@"Problem running operation %@ ... %@",
|
||||
op, localException);
|
||||
}
|
||||
NS_ENDHANDLER
|
||||
[op _finish];
|
||||
}
|
||||
}
|
||||
|
||||
[internal->lock lock];
|
||||
internal->threadCount--;
|
||||
[internal->lock unlock];
|
||||
[pool release];
|
||||
[NSThread exit];
|
||||
}
|
||||
|
||||
/* Check for operations which can be executed and start them.
|
||||
*/
|
||||
- (void) _execute
|
||||
|
@ -943,10 +1024,26 @@ static NSOperationQueue *mainQueue = nil;
|
|||
}
|
||||
else
|
||||
{
|
||||
// FIXME ... use a thread pool again in future.
|
||||
[NSThread detachNewThreadSelector: @selector(start)
|
||||
toTarget: op
|
||||
withObject: nil];
|
||||
NSUInteger pending;
|
||||
|
||||
[internal->cond lock];
|
||||
pending = [internal->starting count];
|
||||
[internal->starting addObject: op];
|
||||
|
||||
/* Create a new thread if all existing threads are busy and
|
||||
* we haven't reached the pool limit.
|
||||
*/
|
||||
if (0 == internal->threadCount
|
||||
|| (pending > 0 && internal->threadCount < POOL))
|
||||
{
|
||||
internal->threadCount++;
|
||||
[NSThread detachNewThreadSelector: @selector(_thread)
|
||||
toTarget: self
|
||||
withObject: nil];
|
||||
}
|
||||
/* Tell the thread pool that there is an operation to start.
|
||||
*/
|
||||
[internal->cond unlockWithCondition: 1];
|
||||
}
|
||||
}
|
||||
[internal->lock unlock];
|
||||
|
|
|
@ -182,16 +182,11 @@ int main()
|
|||
PASS(([obj ran] == YES), "operation ran");
|
||||
PASS(([obj thread] != [NSThread currentThread]), "operation ran in other thread");
|
||||
|
||||
/* Currently we start a new thread for each operation, so this next test
|
||||
* won't pass until we re-implement a thread pool.
|
||||
*/
|
||||
testHopeful = YES;
|
||||
PASS(([cnt count] == 0), "thread did not exit immediately");
|
||||
[obj release];
|
||||
/* Observer behavior on OSX 10.6 is that the thread exits after five seconds ... but who knows what that might change to. */
|
||||
[NSThread sleepForTimeInterval: 6.0];
|
||||
PASS(([cnt count] == 1), "thread exit occurs after six seconds");
|
||||
testHopeful = NO;
|
||||
|
||||
PASS(([NSOperationQueue currentQueue] == [NSOperationQueue mainQueue]), "current queue outside -main is main queue");
|
||||
PASS(([NSOperationQueue mainQueue] != nil), "main queue is not nil");
|
||||
|
|
Loading…
Reference in a new issue