Re: Pausing and terminating a thread
Re: Pausing and terminating a thread
- Subject: Re: Pausing and terminating a thread
- From: Ryan Britton <email@hidden>
- Date: Tue, 30 Aug 2005 17:22:40 -0700
Here's an approach I used when implementing something similar to
Finder's spotlight search window. Hopefully it should give you some
idea of how I did this.
(Some code omitted for compactness)
@interface SomeClass
{
NSLock *aLock;
volatile BOOL stopThread
}
@end
@implementation SomeClass
- (id)init
{
if (self = [super init])
{
aLock = [[NSLock alloc] init];
stopThread = NO;
}
return self;
}
- (void)updateQuery:(NSNotification *)aNotification
{
if ([queryString isEqualToString:@""])
{
return;
}
if (query)
{
[self stopThread];
[lock lock];
MDQueryStop(query);
CFNotificationCenterRemoveObserver
(CFNotificationCenterGetLocalCenter(), NULL,
kMDQueryDidFinishNotification, query);
CFNotificationCenterRemoveObserver
(CFNotificationCenterGetLocalCenter(), NULL,
kMDQueryProgressNotification, query);
CFRelease(query);
[queryResults release];
}
else
{
[self stopThread];
[lock lock];
}
[self willChangeValueForKey:@"queryResults"];
query = MDQueryCreate(kCFAllocatorDefault, (CFStringRef)
queryString, NULL, (CFArrayRef) [NSArray arrayWithObject:(NSString *)
kMDItemFSName]);
CFNotificationCenterAddObserver
(CFNotificationCenterGetLocalCenter(), NULL, &queryUpdated,
kMDQueryProgressNotification, query,
CFNotificationSuspensionBehaviorDrop);
CFNotificationCenterAddObserver
(CFNotificationCenterGetLocalCenter(), NULL, &queryFinished,
kMDQueryDidFinishNotification, query,
CFNotificationSuspensionBehaviorDrop);
queryResults = [[NSMutableArray array] retain];
MDQueryExecute(query, 0);
[self didChangeValueForKey:@"queryResults"];
stopThread = NO;
[lock unlock];
}
- (void)updateExampleList:(NSNotification *)aNotification
{
//Make sure there's not another thread running
[self stopThread];
[lock lock];
stopThread = NO;
MDQueryDisableUpdates(query);
[NSThread detachNewThreadSelector:@selector
(updateInSeparateThread) toTarget:self withObject:nil];
[lock unlock];
}
- (void)stopThread
{
@synchronized(self)
{
stopThread = YES;
}
}
- (void)updateInSeparateThread
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSMutableArray *newResults;
NSMutableDictionary *newItem;
CFStringRef fileName, itemPath, modificationDate;
int i;
CFIndex count;
[lock lock];
if (stopThread)
{
[lock unlock];
[pool release];
return;
}
[self performSelectorOnMainThread:@selector
(willChangeValueForKey:) withObject:@"queryResults" waitUntilDone:YES];
newResults = [NSMutableArray array];
count = MDQueryGetResultCount(query);
for (i = 0; i < count; i++)
{
MDItemRef item = (MDItemRef) MDQueryGetResultAtIndex(query, i);
newItem = [NSMutableDictionary dictionary];
fileName = MDItemCopyAttribute(item, kMDItemFSName);
itemPath = MDItemCopyAttribute(item, kMDItemPath);
modificationDate = MDItemCopyAttribute(item,
kMDItemContentModificationDate);
[newItem setValue:((NSString *) fileName) forKey:(NSString
*) kMDItemFSName];
[newItem setValue:((NSString *) itemPath) forKey:(NSString
*) kMDItemPath];
[newItem setValue:((NSString *) modificationDate) forKey:
(NSString *) kMDItemContentModificationDate];
CFRelease(fileName);
CFRelease(itemPath);
CFRelease(modificationDate);
[newResults addObject:newItem];
if (stopThread)
{
[lock unlock];
[pool release];
return;
}
}
[lock unlock];
[self performSelectorOnMainThread:@selector(updateList:)
withObject:newResults waitUntilDone:YES];
[self performSelectorOnMainThread:@selector
(didChangeValueForKey:) withObject:@"queryResults" waitUntilDone:YES];
[pool release];
}
- (void)updateList:(NSArray *)newList
{
[lock lock];
[queryResults autorelease];
queryResults = [newList retain];
MDQueryEnableUpdates(query);
[lock unlock];
}
On Aug 30, 2005, at 3:18 PM, Ben Haller wrote:
On Aug 30, 2005, at 10:16 AM, Hamish Allan wrote:
On Mon, 29 Aug 2005 23:23:08 -0700, Steve Weller
<email@hidden> wrote:
So I can use a lock to implement the pause -- neat...
However this still requires that my worker thread poll. And doesn't
take care of quitting the worker thread. Any better way?
It's not clear what you would like to be able to do. Do you mean
you want to be able to pause and terminate your worker thread
without performing any tests within its main loop?
Is there not communication between worker and GUI anyway, to
inform of progress?
I've run into the same question. You want a background thread to
do a whole lot of work as fast as possible. Due to user actions or
whatever, though, you may want to pause or terminate the background
thread at some unpredictable time in the future. As far as I was
able to figure out, the background thread must poll to determine if
it is supposed to pause or terminate.
And as an aside: you might think this would be fairly irrelevant;
how long does it take to check a flag every 1/10th of a second, for
example? But the problem is the logic that figures out "I've been
working long enough that it's time to check my flag". That logic
would have to run every time though the loop of whatever your
thread is doing, of course, which is a silly waste of time; so you
end up having to just check the flag every time through your loop,
as that is faster than trying to figure out if it's time to check
your flag yet. If your work loop is doing easy, fast stuff, you
end up checking the flag a *lot*, and it slows down your work
significantly. Unrolling your work loop can help somewhat, but of
course you don't want to do that too much or you'll start causing
cache problems because your code is too big, plus of course
unrolled code is hard to maintain. So it's an annoying problem.
It would sure be nice to have a way of pausing and killing
background threads from the main thread without polling, is what
I'm saying. :->
Ben Haller
Stick Software
_______________________________________________
Do not post admin requests to the list. They will be ignored.
Cocoa-dev mailing list (email@hidden)
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden
_______________________________________________
Do not post admin requests to the list. They will be ignored.
Cocoa-dev mailing list (email@hidden)
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden