Releasing resources at end of NSRunLoop - objective-c

I am trying to release resources allocated in daemon process at the end of it or if someone quits the process.
Lets say,
int main(int argc, const char * argv[])
{
Controller *controller = [[Controller alloc] init];
[controller allocateresources];
[[NSRunLoop currentRunLoop] run];
[controller release];
return 0;
}
Here Controller release will not be called. Quit [SIGTERM Signal] just terminates the runloop. How can I release resources allocated in class Controller at the end of application?
EDIT: I understand that system will claim resources back. The thing, I am trying to solve is something like cross process cooperative locks.

I don't think there is really a guarantee that you will return from the -run method. So you shouldn't rely on this to free the resources. There are other ways to do it. For example, a really low-level solution would be to implement an atexit handler
https://developer.apple.com/library/mac/#documentation/Darwin/Reference/ManPages/man3/atexit.3.html
and do the necessary freeing of the lock there.

Related

When using NSURLConnection in main(), why the connection can not finished?

I'm testing the HTTPFileUploadSample now. Because I want to use it to create a type of command tool line program, so i call the method in the main() function, like this:
int main (int argc, const char * argv[])
{
#autoreleasepool {
Uploader *upl = [Uploader alloc];
[upl initWithURL:[NSURL URLWithString:#"http://localhost/uploader.php"]
filePath:#"/test.txt"
delegate:upl
doneSelector:#selector(onUploadDone)
errorSelector:#selector(onUploadError)];
//[[NSRunLoop currentRunLoop] run];
}
return 0;
}
I found it can create the connection and post request normally, but it can not finish the connection, because it do not call those delegate methods(connection:didReceiveResponse: or connection:didReceiveData: or connectionDidFinishLoading:) at all.
So I call the method [[NSRunLoop currentRunLoop] run] to run loop (as the comment in codes), then everything is ok. I do not know why. Can anybody give me some explanation? Thx!
The runloop is a big event handler infinite loop (well, infinite until it's stopped). It watches various sources and when they generate events it dispatches those events to listeners. This is a very effective way to manage asynchronous operations on a single thread.
NSURLConnection (and many other things in Cocoa) rely on the runloop for their processing. If nothing runs the runloop, then the events aren't processed.

iOS5 crashes during runMode:beforeDate:

I have a problem with compatibility of my application with an iOS5 b7 and GM versions.
The issue occurs in the next lines of code:
do {
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
} while (!done);
App crashes with signal EXC_BAD_ACCESS after some iterations.
The number of passed iterations is random (from 2 till 7).
Also everything works quite well on iOS4 and iOS3.
The same issue occurs in Apple's sample: XMLPerformance Sample.
What do you think about this?
October 12th thousands of users of my app will upgrade to iOS5 and I don't want my app to be with such a strange error in the AppStore.
4 hours passed and I've found the problem. I will describe how I've resolved the problem in XMLPerformance sample.
The problem was in NSAutoreleasePool. There is #property (nonatomic, assign) NSAutoreleasePool *downloadAndParsePool;. When the app starts to download Top300 Paid Apps RSS new thread is created using [NSThread detachNewThreadSelector:#selector(downloadAndParse:) toTarget:self withObject:url];. So in that thread we should keep local autorelease pool. It is done in next way:
- (void)downloadAndParse:(NSURL *)url {
self.downloadAndParsePool = [[NSAutoreleasePool alloc] init];
// initializing internet connection and libxml parser.
if (rssConnection != nil) {
do {
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
} while (!done);
}
// Release resources used only in this thread.
[downloadAndParsePool release];
self.downloadAndParsePool = nil;
}
So in downloadAndParse: everything looks fine. Now let's look in one method that is called when an item from RSS is parsed:
- (void)finishedCurrentSong {
// sending new item to delegate and other ...
countOfParsedSongs++;
// Periodically purge the autorelease pool. The frequency of this action may need to be tuned according to the
// size of the objects being parsed. The goal is to keep the autorelease pool from growing too large, but
// taking this action too frequently would be wasteful and reduce performance.
if (countOfParsedSongs == kAutoreleasePoolPurgeFrequency) {
[downloadAndParsePool release];
self.downloadAndParsePool = [[NSAutoreleasePool alloc] init];
countOfParsedSongs = 0;
}
}
As you see there lines :
[downloadAndParsePool release];
self.downloadAndParsePool = [[NSAutoreleasePool alloc] init];
So exactly that lines causes the exception. If I comment them everything works great.
But I decided not only to comment that lines but also replace NSAutoreleasePool in - (void)downloadAndParse:(NSURL *)url with #autorelease block as it is said that it is more efficient:
- (void)downloadAndParse:(NSURL *)url {
#autoreleasepool {
// initializing internet connection and libxml parser.
if (rssConnection != nil) {
do {
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
} while (!done);
}
// Release resources used only in this thread.
}
}
Now everything works fine. The only problem that I haven't resolved is:
// Periodically purge the autorelease pool. The frequency of this action may need to be tuned according to the
// size of the objects being parsed. The goal is to keep the autorelease pool from growing too large, but
// taking this action too frequently would be wasteful and reduce performance.
So if anybody has any thoughts about this problem can post another one answer and may be try to explain more correctly the bug fix. I will be glad to accept that answer.
Thanks.
This looks like memory problem, please check Apple Technote QA1367 "Finding EXC_BAD_ACCESS bugs in a Cocoa project"
In your code, try this to crash as soon as possible:
[item release], item = nil;
It doesn't solve the problem, just makes the crash happen earlier and hopefully give you a more meaningful callstack to study.
If you're using multi-threading, well... You could try to print "current" thread id into console to verify that everything really is run in thread where you expect them to be running. Especially verify that all UI stuff is in main thread, even when such code is run as side-effect of other code (error popups, maybe).
#include <pthread.h>
- (void)myFunction
{
NSLog(#"Thread (%d)",
pthread_mach_thread_np(pthread_self()));
}
Run your app with Instruments, make sure to change memory verification to happen every 1 or 2 seconds. Slow, but yet again you want to get notified as close to the actual memory problem as possible.
Looking at your code: where did that "done" variable come from and who changes it's value and when? Now it looks pretty magical.
Also you could check the return value of runMode:beforeDate to make sure it was run. If the return value is NO, runLoop was not run at all. Maybe some other part of your code cannot handle such case?
Just my little contribution.
As I've got the same problem, I've discover that in iOS5, you don't need to have your own NSAutoreleasePool in a thread (used by performSelectorOnMainThread).
Then, in your code (a xml parser- same as me), I think you have to separate code from iOS4 and iOS5.
With iOS4, you need NSAutoreleasePool, but not with iOS5.

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

How to join threads in Objective C without using delegates/callback?

Is there a clean way of joining threads in Objective C much like "Thread.join" in Java? I found the method performSelector:onThread:withObject:waitUntilDone: but the limitation of this is I can't call the "blocking" on a different line because I want to do something like this:
[dispatch Thread A];
[process something on main thread];
[wait for Thread A to finish before proceeding];
Thank you in advance.
I'm not aware of any Cocoa API to do this, but it wouldn't be too difficult to do with NSThread, pretty easy to do with a lock, and even easier to do with Grand Central Dispatch.
NSThread
NSThread * otherThread = [[NSThread alloc] initWithTarget:self selector:#selector(methodToPerformInBackground:) object:aParameter];
[otherThread start];
//do some stuff
while ([otherThread isFinished] == NO) {
usleep(1000);
}
[otherThread release];
NSLock
NSLock * lock = [[NSLock alloc] init];
//initiate the background task, which should immediately lock the lock and unlock when done
//do some stuff
[lock lock]; //this will pause until the background stuff unlocks
[lock unlock];
[lock release];
Grand Central Dispatch
dispatch_group_t myGroup = dispatch_group_create();
dispatch_group_async(myGroup, dispatch_get_global_queue(), ^{
//stuff to do in the background
});
//do some stuff
dispatch_group_wait(myGroup, DISPATCH_TIME_FOREVER);
dispatch_release(myGroup);
NSConditionLock is the answer to my question, Sorry Dave DeLong, but I cannot use:
"while ([otherThread isFinished] == NO) "
-- because I need fast continuous processing and cannot use sleep.
NSLock
-- because as you said it "initiate the background task, which should immediately lock the lock and unlock when done", this is not a solution because I tried it and we are not sure if the subthread will execute last before the lock-unlock-release on main thread, I ended up getting random errors.
Grand Central Dispatch
--because it's only available in IOS4 and Snow Leopard 10.6, I'm using a lower version.
But your answer gave me the idea and thank you very much for it, so I just "upped" you.
I ended up doing this:
#define T_START 0
#define T_FINISHED 1
-(void) updateVerticalScopeBackground: (id) aParam {
[lockForThread lock];
NSAutoreleasePool *pool = [NSAutoreleasePool new];
//do something
[pool release];
[lockForThread unlockWithCondition:T_FINISHED];
}
-(void) sumFunc {
lockForThread = [[NSConditionLock alloc]
initWithCondition: T_START];
NSThread* updateVerticalScope = [[NSThread alloc] initWithTarget:self selector:#selector(updateVerticalScopeBackground:) object:nil];
[updateVerticalScope start];
//do some processing
[lockForThread lockWhenCondition:T_FINISHED];
[lockForThread unlockWithCondition:T_FINISHED];
[lockForThread release];
}
You could use NSCondition signal/wait.
Could you use a lock to do this? In other words something like this (pseudocode)
create an object to lock on, visible to both threads
dispatch thread A; thread A immediately takes the lock and keeps it for its duration
process something on main thread
main thread attempts to take the lock (this will block until Thread A releases it)
after acquiring the lock, main thread releases it and continues on
You never want your main thread to be blocked waiting for another thread. At least you don't in any application with a user interface because, if the main thread is blocked, your application is frozen.
It would be far better for the main thread to start the background thread, do the other stuff it needs to do and then return to the run loop. The background thread would notify the main thread of completion by sending -performSelectorOnMainThread:waitUntilDone:

NSThread, AsyncSocket and object deallocation

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