NSThread, AsyncSocket and object deallocation - objective-c

I have a piece of network code that uses AsyncSocket but moves it to a separate runloop. I'm creating this runloop with the following piece of code:
[NSThread detachNewThreadSelector:#selector(_workerLoop) toTarget:self withObject:nil];
and here's how my _workerLoop looks like (they're both in the same class):
-(void)_workerLoop {
workerLoop = [[NSRunLoop currentRunLoop] retain];
while(keepWorkerLoopRunning) {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
[workerLoop runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.5f]];
[pool release];
}
[workerLoop release];
workerLoop = nil;
}
Now, according to the docs, the NSThread will retain the target, and as this thread will only terminate when AsyncSocket disconnects, it's impossible to release and deallocate this object until the socket disconnects.
How can I fix this or maybe I'm doing something wrong?

I've solved this by refactoring the runloop constructor out into own class, referenced by parent class that handles the networking code. This way, parent object is being deallocated, it can stop the thread and release the runloop

Related

How to manage the autorelease pool of a NSRunLoop running in a secondary thread?

In Apple's MVCNetworking sample code, the NetworkManager class includes this method to maintain a run loop in a secondary thread dedicated to network activity (in order to run NSURLConnection asynchronously):
- (void)networkRunLoopThreadEntry
{
while(YES) {
NSAutoreleasePool *pool;
pool = [[NSAutorelease alloc] init];
[[NSRunLoop currentRunLoop] run];
[pool drain];
}
}
Since the run method exits immediately if there is no source attached to the run loop, this looks like an infinite while loop which is going uselessly to consume CPU resources if there is currently no NSURLConnection attached to the run loop.
On the other hand, to keep the run loop active, some suggests to schedule an empty port in the run loop:
- (void)networkRunLoopThreadEntry
{
NSAutoreleasePool *pool = [[NSAutorelease alloc] init];
NSPort *port = [NSPort port];
[[NSRunLoop currentRunLoop] addPort:port forMode:NSRunLoopCommonModes];
[NSRunLoop run];
[pool drain];
}
However, in this case, my worry is that the run method will never exit, which means the pool will never get drained, which means all objects allocated and autoreleased in the secondary thread will leak.
What is the way to go then?
(For the context, as many others, I'm trying to encapsulate an asynchronous NSURLConnection inside a NSOperation, which means it can be triggered outside of the main thread. Also, the MVCNetworking sample code, as well as the WWDC 2010 sessions Network Apps for iPhone OS, seem to suggest it is a good idea to have a unique secondary thread dedicated to network transfers to prevent latency on the main thread.)
You can create a CFRunLoopObserver for the kCFRunLoopBeforeWaiting activity and add it to the run loop. In the observer's callout, release the old pool and create a new one. Untested example:
static void resetPoolCallout(CFRunLoopObserverRef observer, CFRunLoopActivity activity, void *info) {
NSAutoreleasePool **poolPointer = (NSAutoreleasePool **)info;
[*poolPointer release];
*poolPointer = [[NSAutoreleasePool alloc] init];
}
- (void)networkRunLoopThreadEntry {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSPort *port = [NSPort port];
[[NSRunLoop currentRunLoop] addPort:port forMode:NSRunLoopCommonModes];
CFRunLoopObserverContext observerContext = {
.version = 0,
.info = (void*)&pool,
.retain = NULL,
.release = NULL,
.copyDescription = NULL
};
CFRunLoopObserverRef observer = CFRunLoopObserverCreate(NULL, kCFRunLoopBeforeWaiting,
true, 0, resetPoolCallout, &observerContext);
CFRunLoopAddObserver(CFRunLoopGetCurrent(), observer, kCFRunLoopCommonModes);
[[NSRunLoop currentRunLoop] run];
CFRunLoopRemoveObserver(CFRunLoopGetCurrent(), observer, kCFRunLoopCommonModes);
CFRelease(observer);
[pool release];
}

Keep NSThread alive and run NSRunLoop on it

So I'm starting a new NSThread that I want to be able to use later by calling performSelector:onThread:.... From how I understand it calling that methods add that call to the runloop on that thread, so on its next iteration it will pop all these calls and subsequently call them until there is nothing left to call. So I need this kind of functionality, an idle thread ready for work that I just can call upon it. My current code looks like this:
- (void)doInitialize
{
mThread = [[NSThread alloc] initWithTarget:self selector:#selector(runThread) object:nil];
[mthread start];
}
- (void)runThread
{
NSAutoReleasePool *pool = [[NSAutoReleasePool alloc] init];
// From what I understand from the Google machine is that this call should start the
// runloop on this thread, but it DOESN'T. The thread dies and is un-callable
[[NSRunLoop currentRunLoop] run];
[pool drain];
}
- (void)scheduleSomethingOnThread
{
[self performSelector:#selector(hardWork) onThread:mThread withObject:nil waitUntilDone:NO];
}
But the thread is not kept alive, and the performSelector:onThread does not do anything. How do I go about this the right way?
A run loop requires at least one "input source" to run. The main run loop does, but you have to add a source manually to get a secondary run loop's -run method to do anything. There's some documentation on this here.
One naïve way to get this to work would be just to put [[NSRunLoop currentRunLoop] run] in an infinite loop; when there's something to do, it'll do it, and return immediately otherwise. The problem is that the thread will take a decent amount of processor time simply waiting for something to occur.
Another solution is to install an NSTimer on this run loop to keep it alive.
But, if possible, you should use a mechanism designed for this sort of thing. If possible, you may want to use NSOperationQueue for background operations.
this piece of code should force the thread to wait forever
BOOL shouldKeepRunning = YES; // global
NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
[runLoop addPort:[NSMachPort port] forMode:NSDefaultRunLoopMode]; // adding some input source, that is required for runLoop to runing
while (shouldKeepRunning && [runLoop runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]); // starting infinite loop which can be stopped by changing the shouldKeepRunning's value

Objective-C Threading: Exiting a thread, retain problems

I'm trying to create a thread that configures a run loop to run a physics engine through a defined NSTimer. However, I'm having trouble making the thread exit normally (or I think the problem is).
Attached are the relevant portions of my code:
(This code is in a view controller)
(back is called when a button is pressed)
- (void)back {
[timestep invalidate];
exiting = YES;
[self release];
}
- (void)initializePhysicsWorld {
// Initializes the thread to simulate physics interactions.
[NSThread detachNewThreadSelector:#selector(physicsThreadMethod)
toTarget:self
withObject:nil];
}
- (void)physicsThreadMethod {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSRunLoop *myRunLoop = [NSRunLoop currentRunLoop];
timestep = [NSTimer timerWithTimeInterval:1.0f/60.0f
target:self
selector:#selector(step:)
userInfo:nil
repeats:YES];
[myRunLoop addTimer:timestep forMode:NSDefaultRunLoopMode];
while (!exiting) {
CFRunLoopRun();
[pool release];
pool = [[NSAutoreleasePool alloc] init]; // periodically refreshes pool
}
CFRunLoopStop([myRunLoop getCFRunLoop]);
NSLog(#"Thread is going to exit");
[pool release];
}
- (void)dealloc {
if ([self.view superview]) {
[self.view removeFromSuperview];
}
[super dealloc];
}
The engine (the step: function) runs fine, but when I try to exit the loop by running the method back, it would appear that the thread does not release its retain on my view controller (dealloc is not called). I think my thread didn't exit the physicsThreadMethod method as the NSLog does not appear in the console. Dealloc was only called when I run 'back' a second time.
I'm not really sure why this is happening, so I would really appreciate any help. Thanks!
The problem lies in here:
while (!exiting) {
CFRunLoopRun(); //<-- here you start the run loop.
// the lines under this line are NEVER executed. also the while loop does nothing
[pool release];
pool = [[NSAutoreleasePool alloc] init]; // periodically refreshes pool
}
You could use NSOperations to wrap your work, there are already properties defined on this class to do exactly this kind of thing.
If you want to stick with your implementation in a NSThread you have to take a look at the CFRunLoop reference and how to add observers to the run loop.
Does CFRunLoopRun return every step:? CFRunLoopStop or [myRunLoop runUntilDate:] would help.

Objective-C block not being released for background-only applications

I have an application that runs in the background only (by specifying LSBackgroundOnly in the info.plist file).
The problem is, that all blocks that I run on parallel queues are not being released.
The code is executed in a memory-managed environment - no GC is involved.
The (simplified) code looks like below. Blubber is just some dummy class that holds an NSDate for testing. Also, it overwrites retain, release, and dealloc to do some logging:
NSOperationQueue *concurrentQueue = [[NSOperationQueue alloc] init];
[concurrentQueue setMaxConcurrentOperationCount:NSOperationQueueDefaultMaxConcurrentOperationCount];
Blubber *aBlubber = [[Blubber alloc] init];
aBlubber.aDate = [NSDate date];
[concurrentQueue addOperationWithBlock:^{
NSAutoreleasePool *blockPool = [[NSAutoreleasePool alloc] init];
NSDate *test = [aBlubber aDate];
NSLog(#"Block DONE");
[blockPool release];
}];
[aBlubber release];
[concurrentQueue release];
If I change the application to be a normal (i.e. non-backgound) application, I can observe the blocks being released whenever any input is made via the UI (even changing the focus to another window is sufficient).
Since my backgorund app receives input directly over the HID USB driver and it does not have a window or menu bar this does not happen.
Is there any way to manually force the runloop or whatever is responsible to telling the queues to release the finished blocks?
(All other objects that had been retained by the blocks are also not released, creating huge memory leaks. These leaks cannot be spottet by the Leaks or ObjectAllocations tools but the memory consumption can be observed skyrocketing using top.)
One common "gotcha" for autorelease pools is that if the app is building up memory without receiving events, the outermost pool (the one managed by the event loop) won't be draining.
I don't think that should apply here since you're managing your own pool... but just in case, you could try this:
...
//When no events are coming in (i.e. the user is away from their computer), the runloop doesn't iterate, and we accumulate autoreleased objects
[[NSTimer scheduledTimerWithTimeInterval:60.0f target:self selector:#selector(kickRunLoop:) userInfo:nil repeats:YES] retain];
...
- (void) kickRunLoop:(NSTimer *)dummy
{
// Send a fake event to wake the loop up.
[NSApp postEvent:[NSEvent otherEventWithType:NSApplicationDefined
location:NSMakePoint(0,0)
modifierFlags:0
timestamp:0
windowNumber:0
context:NULL
subtype:0
data1:0
data2:0]
atStart:NO];
}
It looks like you are using a stack based block that is used after the block has gone out of scope. The block needs to be copied. The code should work if it is changed to this:
[concurrentQueue addOperationWithBlock:[[^{
NSAutoreleasePool *blockPool = [[NSAutoreleasePool alloc] init];
NSDate *test = [aBlubber aDate];
NSLog(#"Block DONE");
[blockPool release];
}copy]autorelease]];
Take a look at this post for a full writeup on blocks: http://gkoreman.com/blog/2011/02/27/blocks-in-c-and-objective-c/

Multiple threads in iphone

how to create multyple threads in iphone(in single class)
please help me with sample code.
Check out the documentation for NSThread, NSOperationQueue, and the various performSelector... methods defined for NSObject.
NSThread Class reference
An example to run a child thread:
- (void)threadRun
{
// One thread, one autorelease pool. as main thread's pool inside main.c
NSAutoreleasePool *aPool = [[NSAuroreleasePool alloc] init];
// do-job in thread here
[aPool release];
}
- (void)performJobWithThread
{
// Method 1:
NSThread *aThread = [[NSThread alloc] initWithTarget:self
selector:#selector(threadRun)
object:nil];
[aThread start];
/// Release aThread at some point avoid memory leak.
// Method 2:
[NSThread detachNewThreadSelector:#selector:#selector(threadRun)
toTarget:self
withObject:nil];
}
Before using NSThread, it's better to read Threading Programming Guide first. It will tell you about memory management, communication with other thread, ..., etc.
NSOperation and NSOperationQueue are good to design multithread. But I am learning them now and I am unable to talk about them clearly.