The recommended way to exit a thread is to let it exit its entry point routine normally. Although Cocoa, POSIX, and Multiprocessing Services offer routines for killing threads directly, the use of such routines is strongly discouraged. Killing a thread prevents that thread from cleaning up after itself. Memory allocated by the thread could potentially be leaked and any other resources currently in use by the thread might not be cleaned up properly, creating potential problems later.
If you anticipate the need to terminate a thread in the middle of an operation, you should design your threads from the outset to respond to a cancel or exit message. For long-running operations, this might mean stopping work periodically and checking to see if such a message arrived. If a message does come in asking the thread to exit, the thread would then have the opportunity to perform any needed cleanup and exit gracefully; otherwise, it could simply go back to work and process the next chunk of data.
One way to respond to cancel messages is to use a run loop input source to receive such messages. Listing 3-2 shows the structure of how this code might look in your thread’s main entry routine. (The example shows the main loop portion only and does not include the steps for setting up an autorelease pool or configuring the actual work to do.) The example installs a custom input source on the run loop that presumably can be messaged from another one of your threads; for information on setting up input sources, see “Configuring Run Loop Sources.” After performing a portion of the total amount of work, the thread runs the run loop briefly to see if a message arrived on the input source. If not, the run loop exits immediately and the loop continues with the next chunk of work. Because the handler does not have direct access to the exitNow local variable, the exit condition is communicated through a key-value pair in the thread dictionary.
Listing 3-2 Checking for an exit condition during a long job
- (void)threadMainRoutine |
{ |
BOOL moreWorkToDo = YES; |
BOOL exitNow = NO; |
NSRunLoop* runLoop = [NSRunLoop currentRunLoop]; |
// Add the exitNow BOOL to the thread dictionary. |
NSMutableDictionary* threadDict = [[NSThread currentThread] threadDictionary]; |
[threadDict setValue:[NSNumber numberWithBool:exitNow] forKey:@"ThreadShouldExitNow"]; |
// Install an input source. |
[self myInstallCustomInputSource]; |
while (moreWorkToDo && !exitNow) |
{ |
// Do one chunk of a larger body of work here. |
// Change the value of the moreWorkToDo Boolean when done. |
// Run the run loop but timeout immediately if the input source isn't waiting to fire. |
[runLoop runUntilDate:[NSDate date]]; |
// Check to see if an input source handler changed the exitNow value. |
exitNow = [[threadDict valueForKey:@"ThreadShouldExitNow"] boolValue]; |
} |
} |
Last updated: 2008-02-08