• Open Menu Close Menu
  • Apple
  • Shopping Bag
  • Apple
  • Mac
  • iPad
  • iPhone
  • Watch
  • TV
  • Music
  • Support
  • Search apple.com
  • Shopping Bag

Lists

Open Menu Close Menu
  • Terms and Conditions
  • Lists hosted on this site
  • Email the Postmaster
  • Tips for posting to public mailing lists
Re: Pausing and terminating a thread
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

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
  • Follow-Ups:
    • Re: Pausing and terminating a thread
      • From: Ben Haller <email@hidden>
References: 
 >Re: Pausing and terminating a thread (From: Hamish Allan <email@hidden>)
 >Re: Pausing and terminating a thread (From: Ben Haller <email@hidden>)

  • Prev by Date: Re: Apple crash reports
  • Next by Date: Re: What's happening with PNG ? (Solved)
  • Previous by thread: Re: Pausing and terminating a thread
  • Next by thread: Re: Pausing and terminating a thread
  • Index(es):
    • Date
    • Thread