NSRunLoop- Clarification needed
multithreading, nsrunloop, objective-c
Solution
The change you see when you use `run` or `runUntilDate:` instead of `runMode:beforeDate:` is expected. The documentation for `runMode:beforeDate:` says this:
it returns after either the first input source is processed or `limitDate` is reached.
There is an input source responsible for handling the `performSelector:...` requests. So when you send `performSelector:...`, the run loop processes an input source and then returns.
On the other hand, the documentation for `run` says this:
it runs the receiver in the NSDefaultRunLoopMode by repeatedly invoking runMode:beforeDate:. In other words, this method effectively begins an infinite loop that processes data from the run loop’s input sources and timers.
So after the run loop processes the input source for your `performSelector:...` request, it waits for another input source to be ready. It doesn't return. Since it doesn't return, your `while` loop never gets a chance to test `exitThread`.
Your attempt to use `CFRunLoopStop` is a good idea, but unfortunately, the documentation for `run` says this:
If you want the run loop to terminate, you shouldn't use this method. Instead, use one of the other run methods and also check other arbitrary conditions of your own, in a loop.
So you can't rely on `CFRunLoopStop` to make `run` return.
Instead, you can drop to a lower level and use `CFRunLoopRun` to run the run loop, because `CFRunLoopStop` is documented to make that function return:
This function forces `rl` to stop running and return control to the function that called `CFRunLoopRun` or `CFRunLoopRunInMode` for the current run loop activation.
So try this to run your run loop:
while(!exitThread) {
NSLog(@"Thread did some work");
CFRunLoopRun([NSRunLoop currentRunLoop].getCFRunLoop);
}
Problem
I am trying to understand the concept of RunLoops. I have read Apple developer's guide on RunLoops and to some extent I have understood the concept of RunLoops. To make my concept more clearer I wrote a very simple code which uses RunLoops in it. The code can be seen below. ``` - (void)viewDidLoad { [super viewDidLoad]; thread = [[NSThread alloc] initWithTarget:self selector:@selector(testMethod) object:nil]; [thread start]; } - (void)testMethod { NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; NSLog(@"Thread Entered"); NSMachPort* dummyPort = [[NSMachPort alloc] init]; [[NSRunLoop currentRunLoop] addPort:dummyPort forMode:NSDefaultRunLoopMode]; while(!exitThread) { NSLog(@"Thread did some work"); [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]; } [[NSRunLoop currentRunLoop] removePort:dummyPort forMode:NSDefaultRunLoopMode]; [dummyPort release]; NSLog(@"Thread Exited"); [pool drain]; } - (IBAction)doDomeWorkOnBackgroundThread:(id)sender { [self performSelector:@selector(dummyMethod) onThread:thread withObject:nil waitUntilDone:NO]; } - (IBAction)exitThread:(id)sender { [self performSelector:@selector(exitBackgroundThread) onThread:thread withObject:nil waitUntilDone:NO]; } - (void)exitBackgroundThread { exitThread = YES; } - (void)dummyMethod { //Empty } ``` In above code I am creating a background thread and on that background thread I am calling function `testMethod` . Inside `testmethod` I am running a while which checks for BOOL variable `exitThread` and runs the background thread's RunLoop using the `- (BOOL)runMode: beforeDate:` method of NSRunLoop. There are two IBActions which are attached to two buttons. As the name of the IBActions suggest one of them is to `exitThread` and other one is to wake up the thread and execute NSLog statement written in the while loop. The above code runs just as I expected. Whenever `doDomeWorkOnBackgroundThread` method is executed thread wakes up from its runloop,performs the next iteration of the while loop, check for BOOL variable `exitThread` and on finding it value as false goes inside the while loop and executes the NSlog statement. Similarly When `exitThread:` method is executed the `exitThread` variable is set to true which causes the while loop and the thread to exit. However I need few more clarifications : 1) If instead of using `runMode: beforeDate:` in the while loop , I use `run` or `runUntilDate:` method of NSRunLoop, then the thread is never exited when `exitThread:` method is executed. The exitBackgroundThread method is called on the background thread but the while loop never performs it's next iteration(as it does when I use `runMode: beforeDate:`) and hence the thread is never exited. 2) I tried changing `exitBackgroundThread` method to ``` - (void)exitBackgroundThread { exitThread = YES; CFRunLoopStop(CFRunLoopGetCurrent()); } ``` Since `exitBackgroundThread` is executed on background thread CFRunLoopGetCurrent() should give the RunLoop of background thread. So this should ideally stop the run loop of the background thread regardless of whatever method of NSRunLoop I am using to start the RunLoop. So in any case thread must exit on call of above function. But it is just not happening. I know I am missing something here and I am doing a fair amount of googling on my part to find answer to this question but just cant seem to find the right answer. **EDIT I have found this question which is very similar to my first query. It clears my first doubt to much extent.