How dangerous is it to use runModalForWindow from multiple threads? - objective-c

I have a memory corruption error (I suspect), which is resulting in a program crash after specific UI actions. This is a Cocoa Objective-C application and does not use GC.
After many hours of debugging, I found a possible reason for the crash:
DiscSelectPopup *popupSelect = [[DiscSelectPopup alloc] initWithDataList:dataList count:count];
NSInteger result = [NSApp runModalForWindow:popupSelect.window];
The above popup routine is executed from a secondary thread. This thread is created and started every time the user clicks on a button. So, we can have several modal popup show up simultaneously.
When I run the program in debug mode with MallocStackLogging=1 and MallocStackLoggingNoCompact=1, it prints a malloc error log message at the runModalForWindow: call (but not always).
malloc: *** error for object 0xbc65840: double free
.....
malloc: *** error for object 0xbc547e0: pointer being freed was not allocated
Is it really bad to use runModalForWindow: from a secondary thread?
Could it be the reason for the crash?

Is it really bad to use runModalForWindow from the secondary thread?
Yes. UI stuff needs to happen on the main thread.
You also shouldn't use runModalForWindow: unless you specifically want to block all of the other windows in your application (essentially freezing your app except for that window). Just show the window. If you want to block a specific window (or your app is single-window), begin it as a sheet.
Edit: Looking again at the question, this caught my eye:
The above popup routine is executed from a secondary thread.
Don't do that. To show a window, just show it. Receive the action message from the button on the main thread, and then do only the actual work—if anything—on a secondary thread.
Note that showing the window will not block any other windows or anything else you're doing unless you specifically make it do so (i.e., use runModalForWindow:). If you show the window in the normal way, all your windows continue to work normally. Any timers and observers and similar things you've scheduled on the main thread also continue to work. You don't need to create threads or do anything else special for this; it all just works by default.
If the work that you'll eventually do may take a non-trivial amount of time, then you should put that on a secondary thread, only when it comes time to do it. You should also look into whether or not it'd be easier or better to construct as operation objects or blocks than as raw threads. It probably will.

Using valgrind memcheck, I concluded that the secondary thread runModalForWindow: calls are not directly connected with the memory corruption problem.
Yes, it is bad coding to manipulate UI components from non-main threads but such behavior alone cannot crash the program.
The malloc error message in the question was due to the mistakenly double released popup window object.
By the way, real cause of the memory corruption was the mismatched malloc/free call (freeing not malloced memory pointer).

Related

If performSelectorOnMainThread:waitUntilDone: is called from the main thread, when will it execute?

I'm programming an application that makes use of asynchronous web requests using NSURLConnection, so I have multiple threads running. To ensure that the main logic of my app happens on one thread, I am making heavy use of performSelectorOnMainThread:waitUntilDone:. Sometimes though, I am running this on the main thread, which piqued my curiosity.
If performSelectorOnMainThread:waitUntilDone: is called while in the main thread? Does it act the same as just performSelector:? What if waitUntilDone: is YES? What if it is NO?
EDIT: I have found that when waitUntilDone: is YES, the selector is executed (almost) immediately, but I cannot figure out when it is executed if waitUntilDone: is NO.
performSelectorOnMainThread:withObject:waitUntilDone:
is a method to deliver message on main thread of your application. Here boolean value in parameter waitUntilDone: specifies that whether you want to block your main thread to execute specified selector or not.
for example -
if you written these two lines-
[self performSelectorOnMainThread:#selector(print) withObject:nil waitUntilDone:YES];
NSLog(#"Hello iPhone");
and this is the print method -
- (void) print
{
NSLog(#"Hello World");
}
then you will get this o/p
Hello World
Hello iPhone
so it first pause the execution of your main thread and print "Hello World" and then execute main thread again and print "Hello iPhone" because you specified YES in waitUntilDone:
but if you specified NO in waitUntilDone: then it will print like this -
Hello iPhone
Hello World
it clearly indicates that it put your request of executing the specified selector in a queue and as OS gets its main thread free it executed you request.
Calling performSelectorOnMainThread:withObject:waitUntilDone: either from main thread or a secondary thread doesn't make any difference in it's execution, it depends on what you specified in waitUntilDone:
for more info -
NSObject Class Reference
If the current thread is also the main thread, and you pass YES,
the message is performed immediately, otherwise the perform is
queued to run the next time through the run loop.
If YES, it can be performed before performSelectorOnMainThread:withObject:waitUntilDone: returns.
I have found that when waitUntilDone: is YES, the selector is executed (almost) immediately, but I cannot figure out when it is executed if waitUntilDone: is NO.
The bit about the run loop: Your main thread has a run loop. This more or less prevents a thread from exiting. A run loop manages a todo list. When its work is complete, it suspends execution of that thread for some time. Then it wakes up later and sees if has work to do.
The amount of work can vary greatly (e.g. it may do some really heavy drawing or file i/o between the time it awakes and the point your selector is performed. Therefore, it's not a good tool for really precise timing, but it should be enough to know how it works and how the implementations adds the work to the run loop.
http://developer.apple.com/library/ios/#documentation/cocoa/Conceptual/Multithreading/RunLoopManagement/RunLoopManagement.html
If waitUntilDone: is YES it acts as an immediate function call.
If waitUntilDone: is NO then it queues the call along with all other threads' calls.
This method queues the message on the run loop of the main thread
using the common run loop modes—that is, the modes associated with the
NSRunLoopCommonModes constant. As part of its normal run loop
processing, the main thread dequeues the message (assuming it is
running in one of the common run loop modes) and invokes the desired
method.
As noted above, things like drawing and I/O are prioritized over anything in queues. Once the main thread gets around to having time for queue service in the next event loop, there's a couple other details that make it not quite as simple as counting on first in first out:
1) dispatch_async() blocks ignore modes.
2) The performSelector variants with a specific mode argument -- event tracking, say -- may take precedence over ones with the default common modes argument in a loop running in that specific mode.
As a general rule, if you want predictable timing behaviours you should use the low level GCD dispatch functions that don't take account of higher level considerations like run loop modes.

What does NSManagedContext reset do?

Here's my scenario: I have a thread running heavy calculations, saving the results via core data at the end. I have the thread set up with it's own autorelease pool and it's own NSManagedContext created within the thread. The user can change the inputs to the calculation on the main thread, in which case the calculation thread is terminated (via regular checks of a NSLocked variable) and relaunched with the new inputs. Everything is working fine here.
For performance reasons, the calculation thread doesn't have an undo manager and there is only one context save at the very end. If a termination command is detected I don't want to save the results. Right now I'm just skipping the context save and releasing it, which seems to work fine.
I noticed, however, that there's a reset method for NSManagedContext. Apple's documentation on this method isn't very helpful to me. It simply states that it returns the receiver's contents to it's base state and that all the receiver's managed objects are "forgotten".
What does that mean? Is it the equivalent to reverting to the last saved version? Is an undo manager required for proper operation of this method? Any reason I should use this method instead of what I'm doing now?
It sounds like you are using the context to cache changes independent of the context on the main thread, and if you don't want those changes to be recorded, you just throw them out by deleting the "local" context. This is good enough for the scenario you are describing. -reset might be useful if you didn't want to relaunch the background thread, but just start over using the same thread (and context), but with new inputs. Since you launch a new thread (thus creating a new NSManagedObjectContext on it), -reset is probably not very useful for you in this scenario. You already pretty much doing it as Apple recommends in several of their sample codes.

How to terminate performSelectorInBackground: thread?

How can I kill a thread created by performSelectorInBackground:withObject: from the main thread? I need to force termination of freezing threads.
You cannot kill background threads from the main thread, the method that is executing in a background thread has to return for the thread to end.
Your actual problem seems to be that your background thread is freezing, you should solve that instead of trying to work around it.
I'm not sure if this may help but here goes:
Assuming you're calling that performSelector call from class A. And assuming that class A is about to be released from memory in class B (which is where if the selector hasn't been performed yet, you might be getting a crash - Hence you're posting this question on SO):
Wherever you're releasing A from B, do this:
[NSObject cancelPreviousPerformRequestsWithTarget:A];
Apple documentation says
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.

Live object is garbage collected?

I am using Garbage collector in my Cocoa based application on Mac OS X. It has 100s of threads running and synchronization is done using Operation Queue.
After a long run, one of the object is garbaged and application will crash.
Checking to see if the object is non nil also fails as the the object is invalid and contains some garbage value. Calling a method on the object leads to crash.
Anyone please help me in debugging the issue.
Thank you......................
I am using Garbage collector in my
Cocoa based application on Mac OS X.
It has 100s of threads running and
synchronization is done using
Operation Queue.
More likely than not, the bug lies within the seemingly rather overly concurrent nature of your code. Running 100s of threads on a machine with "only" double digits worth of cores (if that) is unlikely to be very efficient and, of course, keeping everything properly in sync is going to be rather difficult.
The best place to start is to turn on Malloc stack logging and use malloc_history to find out what events occurred at the address that went south.
Also, there were fixes in 10.6.5 that impacted GC correctness.
If you can change the code of the garbage collected object, then override the finalize method like this, to get some information:
- (void) finalize
{
NSLog(#"Finalizing!\n%#", [[NSThread callStackSymbols] componentsJoinedByString:#"\n"]);
//if you put here a breakpoint, you can check the supposed references to this object
[super finalize];
}

Low-level details of the implementation of performSelectorOnMainThread:

Was wondering if anyone knows, or has pointers to good documentation that discusses, the low-level implementation details of Cocoa's 'performSelectorOnMainThread:' method.
My best guess, and one I think is probably pretty close, is that it uses mach ports or an abstraction on top of them to provide intra-thread communication, passing selector information along as part of the mach message.
Right? Wrong? Thanks!
Update 09:39AMPST
Thank you Evan DiBiase and Mecki for the answers, but to clarify: I understand what happens in the run loop, but what I'm looking for an answer to is; "where is the method getting queued? how is the selector information getting passed into the queue?" Looking for more than Apple's doc info: I've read 'em
Update 14:21PST
Chris Hanson brings up a good point in a comment: my objective here is not to learn the underlying mechanisms in order to take advantage of them in my own code. Rather, I'm just interested in a better conceptual understanding of the process of signaling another thread to execute code. As I said, my own research leads me to believe that it's takes advantage of mach messaging for IPC to pass selector information between threads, but I'm specifically looking for concrete information on what is happening, so I can be sure I'm understanding things correctly. Thanks!
Update 03/06/09
I've opened a bounty on this question because I'd really like to see it answered, but if you are trying to collect please make sure you read everything, including all currently posed answers, comments to both these answers and to my original question, and the update text I posted above. I'm look for the lowest-level detail of the mechanism used by performSelectorOnMainThread: and the like, and as I mentioned earlier, I suspect it has something to do with Mach ports but I'd really like to know for sure. The bounty will not be awarded unless I can confirm the answer given is correct. Thanks everyone!
Yes, it does use Mach ports. What happens is this:
A block of data encapsulating the perform info (the target object, the selector, the optional object argument to the selector, etc.) is enqueued in the thread's run loop info. This is done using #synchronized, which ultimately uses pthread_mutex_lock.
CFRunLoopSourceSignal is called to signal that the source is ready to fire.
CFRunLoopWakeUp is called to let the main thread's run loop know it's time to wake up. This is done using mach_msg.
From the Apple docs:
Version 1 sources are managed by the run loop and kernel. These sources use Mach ports to signal when the sources are ready to fire. A source is automatically signaled by the kernel when a message arrives on the source’s Mach port. The contents of the message are given to the source to process when the source is fired. The run loop sources for CFMachPort and CFMessagePort are currently implemented as version 1 sources.
I'm looking at a stack trace right now, and this is what it shows:
0 mach_msg
1 CFRunLoopWakeUp
2 -[NSThread _nq:]
3 -[NSObject(NSThreadPerformAdditions) performSelector:onThread:withObject:waitUntilDone:modes:]
4 -[NSObject(NSThreadPerformAdditions) performSelectorOnMainThread:withObject:waitUntilDone:]
Set a breakpoint on mach_msg and you'll be able to confirm it.
One More Edit:
To answer the question of the comment:
what IPC mechanism is being used to
pass info between threads? Shared
memory? Sockets? Mach messaging?
NSThread stores internally a reference to the main thread and via that reference you can get a reference to the NSRunloop of that thread. A NSRunloop internally is a linked list and by adding a NSTimer object to the runloop, a new linked list element is created and added to the list. So you could say it's shared memory, the linked list, that actually belongs to the main thread, is simply modified from within a different thread. There are mutexes/locks (possibly even NSLock objects) that will make sure editing the linked list is thread-safe.
Pseudo code:
// Main Thread
for (;;) {
lock(runloop->runloopLock);
task = NULL;
do {
task = getNextTask(runloop);
if (!task) {
// function below unlocks the lock and
// atomically sends thread to sleep.
// If thread is woken up again, it will
// get the lock again before continuing
// running. See "man pthread_cond_wait"
// as an example function that works
// this way
wait_for_notification(runloop->newTasks, runloop->runloopLock);
}
} while (!task);
unlock(runloop->runloopLock);
processTask(task);
}
// Other thread, perform selector on main thread
// selector is char *, containing the selector
// object is void *, reference to object
timer = createTimerInPast(selector, object);
runloop = getRunloopOfMainThread();
lock(runloop->runloopLock);
addTask(runloop, timer);
wake_all_sleeping(runloop->newTasks);
unlock(runloop->runloopLock);
Of course this is oversimplified, most details are hidden between functions here. E.g. getNextTask will only return a timer, if the timer should have fired already. If the fire date for every timer is still in the future and there is no other event to process (like a keyboard, mouse event from UI or a sent notification), it would return NULL.
I'm still not sure what the question is. A selector is nothing more than a C string containing the name of a method being called. Every method is a normal C function and there exists a string table, containing the method names as strings and function pointers. That are the very basics how Objective-C actually works.
As I wrote below, a NSTimer object is created that gets a pointer to the target object and a pointer to a C string containing the method name and when the timer fires, it finds the right C method to call by using the string table (hence it needs the string name of the method) of the target object (hence it needs a reference to it).
Not exactly the implementation, but pretty close to it:
Every thread in Cocoa has a NSRunLoop (it's always there, you never need to create on for a thread). PerformSelectorOnMainThread creates a NSTimer object like this, one that fires only once and where the time to fire is already located in the past (so it needs firing immediately), then gets the NSRunLoop of the main thread and adds the timer object there. As soon as the main thread goes idle, it searches for the next event in its Runloop to process (or goes to sleep if there is nothing to process and being woken up again as soon as an event is added) and performs it. Either the main thread is busy when you schedule the call, in which case it will process the timer event as soon as it has finished its current task or it is sleeping at the moment, in which case it will be woken up by adding the event and processes it immediately.
A good source to look up how Apple is most likely doing it (nobody can say for sure, as after all its closed source) is GNUStep. Since the GCC can handle Objective-C (it's not just an extension only Apple ships, even the standard GCC can handle it), however, having Obj-C without all the basic classes Apple ships is rather useless, the GNU community tried to re-implement the most common Obj-C classes you use on Mac and their implementation is OpenSource.
Here you can download a recent source package.
Unpack that and have a look at the implementation of NSThread, NSObject and NSTimer for details. I guess Apple is not doing it much different, I could probably prove it using gdb, but why would they do it much different than that approach? It's a clever approach that works very well :)
The documentation for NSObject's performSelectorOnMainThread:withObject:waitUntilDone: method says:
This method queues the message on the run loop of the main thread using the default run loop modes—that is, the modes associated with the NSRunLoopCommonModes constant. As part of its normal run loop processing, the main thread dequeues the message (assuming it is running in one of the default run loop modes) and invokes the desired method.
As Mecki said, a more general mechanism that could be used to implement -performSelectorOn… is NSTimer.
NSTimer is toll-free bridged to CFRunLoopTimer. An implementation of CFRunLoopTimer – although not necessarily the one actually used for normal processes in OS X – can be found in CFLite (open-source subset of CoreFoundation; package CF-476.14 in the Darwin 9.4 source code. (CF-476.15, corresponding to OS X 10.5.5, is not yet available.)