mirror of
https://github.com/gnustep/libs-performance.git
synced 2025-02-23 11:51:20 +00:00
Add a simple thread pooling utility.
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/performance/trunk@31464 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
parent
1b8b70f13e
commit
c6901d7862
6 changed files with 349 additions and 2 deletions
|
@ -1,4 +1,10 @@
|
||||||
2010-10-30 Richard Frith-Macdonald <rfm@gnu.org>
|
2010-10-01 Richard Frith-Macdonald <rfm@gnu.org>
|
||||||
|
|
||||||
|
* GSIOThreadPool.h:
|
||||||
|
* GSIOThreadPool.m:
|
||||||
|
Add new methed class for pooling threads to handle I/O and timers.
|
||||||
|
|
||||||
|
2010-09-30 Richard Frith-Macdonald <rfm@gnu.org>
|
||||||
|
|
||||||
* GSThreadPool.h:
|
* GSThreadPool.h:
|
||||||
* GSThreadPool.m:
|
* GSThreadPool.m:
|
||||||
|
|
|
@ -36,6 +36,7 @@ Performance_INTERFACE_VERSION=0.3
|
||||||
|
|
||||||
Performance_OBJC_FILES += \
|
Performance_OBJC_FILES += \
|
||||||
GSCache.m \
|
GSCache.m \
|
||||||
|
GSIOThreadPool.m \
|
||||||
GSLinkedList.m \
|
GSLinkedList.m \
|
||||||
GSThreadPool.m \
|
GSThreadPool.m \
|
||||||
GSThroughput.m \
|
GSThroughput.m \
|
||||||
|
@ -46,6 +47,7 @@ Performance_OBJC_FILES += \
|
||||||
|
|
||||||
Performance_HEADER_FILES += \
|
Performance_HEADER_FILES += \
|
||||||
GSCache.h \
|
GSCache.h \
|
||||||
|
GSIOThreadPool.h \
|
||||||
GSLinkedList.h \
|
GSLinkedList.h \
|
||||||
GSThreadPool.h \
|
GSThreadPool.h \
|
||||||
GSThroughput.h \
|
GSThroughput.h \
|
||||||
|
@ -55,6 +57,7 @@ Performance_HEADER_FILES += \
|
||||||
|
|
||||||
Performance_AGSDOC_FILES += \
|
Performance_AGSDOC_FILES += \
|
||||||
GSCache.h \
|
GSCache.h \
|
||||||
|
GSIOThreadPool.h \
|
||||||
GSLinkedList.h \
|
GSLinkedList.h \
|
||||||
GSThreadPool.h \
|
GSThreadPool.h \
|
||||||
GSThroughput.h \
|
GSThroughput.h \
|
||||||
|
|
92
GSIOThreadPool.h
Normal file
92
GSIOThreadPool.h
Normal file
|
@ -0,0 +1,92 @@
|
||||||
|
#if !defined(INCLUDED_GSIOTHREADPOOL)
|
||||||
|
#define INCLUDED_GSIOTHREADPOOL 1
|
||||||
|
/**
|
||||||
|
Copyright (C) 2010 Free Software Foundation, Inc.
|
||||||
|
|
||||||
|
Written by: Richard Frith-Macdonald <rfm@gnu.org>
|
||||||
|
Date: September 2010
|
||||||
|
|
||||||
|
This file is part of the Performance Library.
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 3 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with this library; if not, write to the Free
|
||||||
|
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA.
|
||||||
|
*/
|
||||||
|
#import <Foundation/NSObject.h>
|
||||||
|
|
||||||
|
@class NSThread;
|
||||||
|
@class NSLock;
|
||||||
|
|
||||||
|
/** This class provides a thread pool for performing methods which need to
|
||||||
|
* make use of a runloop for I/O and/or timers.<br />
|
||||||
|
* Operations are performed on these threads using the standard
|
||||||
|
* -performSelector:onThread:withObject:waitUntilDone: method ... the
|
||||||
|
* pool is simply used to keep track of allocation of threads so that
|
||||||
|
* you can share jobs between them.
|
||||||
|
*/
|
||||||
|
@interface GSIOThreadPool : NSObject
|
||||||
|
{
|
||||||
|
NSLock *poolLock;
|
||||||
|
NSMutableArray *threads;
|
||||||
|
NSTimeInterval timeout;
|
||||||
|
NSUInteger maxThreads;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns an instance intended for sharing between sections of code which
|
||||||
|
* wish to make use of threading by performing operations in other threads,
|
||||||
|
* but which don't mind operations being interleaved with those belonging to
|
||||||
|
* oither sections of code.<br />
|
||||||
|
* Always returns the same instance whenever the method is called.
|
||||||
|
*/
|
||||||
|
+ (GSIOThreadPool*) sharedPool;
|
||||||
|
|
||||||
|
/** Seects a thread from the pool to be used for some job.
|
||||||
|
*/
|
||||||
|
- (NSThread*) acquireThread;
|
||||||
|
|
||||||
|
/** Returns the acquire count for the specified thread.
|
||||||
|
*/
|
||||||
|
- (NSUInteger) countForThread: (NSThread*)aThread;
|
||||||
|
|
||||||
|
/** Returns the currently configured maximum number of threads in the pool.
|
||||||
|
*/
|
||||||
|
- (NSUInteger) maxThreads;
|
||||||
|
|
||||||
|
/** Specify the maximum number of threads in the pool (the actual number
|
||||||
|
* used may be lower than this value).<br />
|
||||||
|
* Default is 2.<br />
|
||||||
|
* The pool creates threads on demand up to the specified limit (or a lower
|
||||||
|
* limit if dictated by system resources) but will not destroy idle threads
|
||||||
|
* unless the limit is subsequently lowered.<br />
|
||||||
|
* Setting a value of zero means that operations are performed in the
|
||||||
|
* main thread.
|
||||||
|
*/
|
||||||
|
- (void) setThreads: (NSUInteger)max;
|
||||||
|
|
||||||
|
/** Specifies the timeout allowed for a thread to close down when the pool
|
||||||
|
* is deallocated or has its size decreased. Any operations in progress in
|
||||||
|
* the thread need to close down within this period.
|
||||||
|
*/
|
||||||
|
- (void) setTimeout: (NSTimeInterval)t;
|
||||||
|
|
||||||
|
/** Returns the current timeout set for the pool.
|
||||||
|
*/
|
||||||
|
- (NSTimeInterval) timeout;
|
||||||
|
|
||||||
|
/** Releases a thread previously selected from the pool.
|
||||||
|
*/
|
||||||
|
- (void) unacquireThread: (NSThread*)aThread;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
#endif
|
245
GSIOThreadPool.m
Normal file
245
GSIOThreadPool.m
Normal file
|
@ -0,0 +1,245 @@
|
||||||
|
/**
|
||||||
|
Copyright (C) 2010 Free Software Foundation, Inc.
|
||||||
|
|
||||||
|
Written by: Richard Frith-Macdonald <rfm@gnu.org>
|
||||||
|
Date: September 2010
|
||||||
|
|
||||||
|
This file is part of the Performance Library.
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 3 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with this library; if not, write to the Free
|
||||||
|
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#import <Foundation/NSArray.h>
|
||||||
|
#import <Foundation/NSDate.h>
|
||||||
|
#import <Foundation/NSLock.h>
|
||||||
|
#import <Foundation/NSRunLoop.h>
|
||||||
|
#import <Foundation/NSThread.h>
|
||||||
|
#import <Foundation/NSTimer.h>
|
||||||
|
#import "GSIOThreadPool.h"
|
||||||
|
|
||||||
|
@interface GSIOThread : NSThread
|
||||||
|
{
|
||||||
|
NSTimer *timer;
|
||||||
|
@public
|
||||||
|
NSUInteger count;
|
||||||
|
}
|
||||||
|
- (void) exit: (NSTimer*)t;
|
||||||
|
- (void) run;
|
||||||
|
- (void) terminate: (NSDate*)when;
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation GSIOThread
|
||||||
|
|
||||||
|
/* Force termination of this thread.
|
||||||
|
*/
|
||||||
|
- (void) exit: (NSTimer*)t
|
||||||
|
{
|
||||||
|
[NSThread exit];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id) init
|
||||||
|
{
|
||||||
|
self = [super initWithTarget: self selector: @selector(run) object: nil];
|
||||||
|
if (nil != self)
|
||||||
|
{
|
||||||
|
[self start];
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Run the thread's main runloop until terminated.
|
||||||
|
*/
|
||||||
|
- (void) run
|
||||||
|
{
|
||||||
|
NSDate *when = [NSDate distantFuture];
|
||||||
|
NSTimeInterval delay = [when timeIntervalSinceNow];
|
||||||
|
|
||||||
|
timer = [NSTimer scheduledTimerWithTimeInterval: delay
|
||||||
|
target: self
|
||||||
|
selector: @selector(exit:)
|
||||||
|
userInfo: nil
|
||||||
|
repeats: NO];
|
||||||
|
[[NSRunLoop currentRunLoop] run];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* End execution of the thread by the specified date.
|
||||||
|
*/
|
||||||
|
- (void) terminate: (NSDate*)when
|
||||||
|
{
|
||||||
|
NSTimeInterval delay = [when timeIntervalSinceNow];
|
||||||
|
|
||||||
|
[timer invalidate];
|
||||||
|
if (delay > 0.0)
|
||||||
|
{
|
||||||
|
timer = [NSTimer scheduledTimerWithTimeInterval: delay
|
||||||
|
target: self
|
||||||
|
selector: @selector(exit:)
|
||||||
|
userInfo: nil
|
||||||
|
repeats: NO];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
timer = nil;
|
||||||
|
[self exit: nil];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@end
|
||||||
|
|
||||||
|
|
||||||
|
@implementation GSIOThreadPool
|
||||||
|
|
||||||
|
static GSIOThreadPool *shared = nil;
|
||||||
|
|
||||||
|
/* Return the thread with the lowest usage.
|
||||||
|
*/
|
||||||
|
static GSIOThread *
|
||||||
|
best(NSMutableArray *a)
|
||||||
|
{
|
||||||
|
NSUInteger c = [a count];
|
||||||
|
NSUInteger l = NSNotFound;
|
||||||
|
GSIOThread *t = nil;
|
||||||
|
|
||||||
|
while (c-- > 0)
|
||||||
|
{
|
||||||
|
GSIOThread *o = [a objectAtIndex: c];
|
||||||
|
|
||||||
|
if (o->count < l)
|
||||||
|
{
|
||||||
|
t = o;
|
||||||
|
l = o->count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (void) initialize
|
||||||
|
{
|
||||||
|
if ([GSIOThreadPool class] == self && nil == shared)
|
||||||
|
{
|
||||||
|
shared = [self new];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (GSIOThreadPool*) sharedPool
|
||||||
|
{
|
||||||
|
return shared;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSThread*) acquireThread
|
||||||
|
{
|
||||||
|
GSIOThread *t;
|
||||||
|
|
||||||
|
[poolLock lock];
|
||||||
|
t = best(threads);
|
||||||
|
if (t->count > 0 && [threads count] < maxThreads)
|
||||||
|
{
|
||||||
|
t = [GSIOThread new];
|
||||||
|
[threads addObject: t];
|
||||||
|
[t release];
|
||||||
|
}
|
||||||
|
t->count++;
|
||||||
|
[poolLock unlock];
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSUInteger) countForThread: (NSThread*)aThread
|
||||||
|
{
|
||||||
|
NSUInteger count = 0;
|
||||||
|
|
||||||
|
[poolLock lock];
|
||||||
|
if ([threads indexOfObjectIdenticalTo: aThread] != NSNotFound)
|
||||||
|
{
|
||||||
|
count = ((GSIOThread*)aThread)->count;
|
||||||
|
}
|
||||||
|
[poolLock unlock];
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) dealloc
|
||||||
|
{
|
||||||
|
GSIOThread *thread;
|
||||||
|
NSDate *when = [NSDate dateWithTimeIntervalSinceNow: timeout];
|
||||||
|
|
||||||
|
[poolLock lock];
|
||||||
|
while ((thread = [threads lastObject]) != nil)
|
||||||
|
{
|
||||||
|
[thread performSelector: @selector(terminate:)
|
||||||
|
onThread: thread
|
||||||
|
withObject: when
|
||||||
|
waitUntilDone: NO];
|
||||||
|
[threads removeLastObject];
|
||||||
|
}
|
||||||
|
[threads release];
|
||||||
|
[poolLock unlock];
|
||||||
|
[poolLock release];
|
||||||
|
[super dealloc];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id) init
|
||||||
|
{
|
||||||
|
if ((self = [super init]) != nil)
|
||||||
|
{
|
||||||
|
poolLock = [NSLock new];
|
||||||
|
threads = [NSMutableArray new];
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSUInteger) maxThreads
|
||||||
|
{
|
||||||
|
return maxThreads;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) setThreads: (NSUInteger)max
|
||||||
|
{
|
||||||
|
[poolLock lock];
|
||||||
|
if (max != maxThreads)
|
||||||
|
{
|
||||||
|
maxThreads = max;
|
||||||
|
while ([threads count] > maxThreads)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
[poolLock unlock];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) setTimeout: (NSTimeInterval)t
|
||||||
|
{
|
||||||
|
timeout = t;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSTimeInterval) timeout
|
||||||
|
{
|
||||||
|
return timeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) unacquireThread: (NSThread*)aThread
|
||||||
|
{
|
||||||
|
[poolLock lock];
|
||||||
|
if ([threads indexOfObjectIdenticalTo: aThread] != NSNotFound)
|
||||||
|
{
|
||||||
|
if (0 == ((GSIOThread*)aThread)->count)
|
||||||
|
{
|
||||||
|
[poolLock unlock];
|
||||||
|
[NSException raise: NSInternalInconsistencyException
|
||||||
|
format: @"-unacquireThread: called too many times"];
|
||||||
|
}
|
||||||
|
((GSIOThread*)aThread)->count--;
|
||||||
|
}
|
||||||
|
[poolLock unlock];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
|
@ -61,7 +61,7 @@ static GSThreadPool *shared = nil;
|
||||||
|
|
||||||
+ (void) initialize
|
+ (void) initialize
|
||||||
{
|
{
|
||||||
if ([GSThreadPool class] == self)
|
if ([GSThreadPool class] == self && nil == shared)
|
||||||
{
|
{
|
||||||
shared = [self new];
|
shared = [self new];
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#import "GSCache.h"
|
#import "GSCache.h"
|
||||||
|
#import "GSIOThreadPool.h"
|
||||||
#import "GSLinkedList.h"
|
#import "GSLinkedList.h"
|
||||||
#import "GSThreadPool.h"
|
#import "GSThreadPool.h"
|
||||||
#import "GSThroughput.h"
|
#import "GSThroughput.h"
|
||||||
|
|
Loading…
Reference in a new issue