performSelector:OnThread:waitUntilDone not executing the selector all the time - objective-c

I have an app where the network activity is done in its separate thread (and the network thread continuously gets data from the server and updates the display - the display calls are made back on the main thread). When the user logs out, the main thread calls a disconnect method on the network thread as follows:
[self performSelector:#selector(disconnectWithErrorOnNetworkThread:) onThread:nThread withObject:e waitUntilDone:YES];
This selector gets called most of the time and everything works fine. However, there are times (maybe 2 out of ten times) that this call never returns (in other words the selector never gets executed) and the thread and the app just hang. Anyone know why performSelector is behaving erratically?
Please note that I need to wait until the call gets executed, that's why waitUntilDone is YES, so changing that to NO is not an option for me. Also the network thread has its run loop running (I explicitly start it when the thread is created).
Please also note that due to the continuous nature of the data transfer, I need to explicitly use NSThreads and not GCD or Operations queues.

That'll hang if:
it is attempting to perform a selector on the same thread the method was called from
the call to perform the selector is to a thread from which a synchronous call was made that triggered the perform selector
When your program is hung, have a look at the backtraces of all threads.
Note that when implementing any kind of networking concurrency, it is generally really bad to have synchronous calls from the networking code into the UI layers or onto other threads. The networking thread needs to be very responsive and, thus, just like blocking the main thread is bad, anything that can block the networking thread is a bad, too.
Note also that some APIs with callbacks don't necessarily guarantee which thread the callback will be delivered on. This can lead to intermittent lockups, as described.
Finally, don't do any active polling. Your networking thread should be fully quiescent unless some event arrives. Any kind of looped polling is bad for battery life and responsiveness.

Related

Objective-C NSRunLoop & NotificationCenterDelegate not functional when spawned on Rust worker thread

I'm currently trying to use Rust C interop in order to send actional desktop notifications (using a modified version of this lib). The main goal here would be to handle these notification sending events on separate threads like so:
thread::spawn(move || unsafe {
sys::sendNotification(
NSString::from_str(&title).deref(),
NSString::from_str(&message).deref(),
NSString::from_str(&uri).deref(),
NSString::from_str(&img.unwrap_or_default()).deref(),
);
});
This would allow me to have multiple notification 'handlers' running at the same time (vs. just being able to have a single notification displayed at once), and would also allow my main process to run without being blocked. Given the nature of the program (web-scraper), I don't want scraping halted whenever a notification is being displayed.
That said, this approach is somewhat problematic because the underlying obj-c code relies on NSRunLoop to handle click events (e.g., user clicks on the action to open a web page) through the created NotificationCenterDelegate instance. Per my knowledge (feel free to fact-check me on this I'm not familiar with obj-c), NSRunLoops only operate on the main thread and this code is rendered useless if ran on a worker... The notification still sends in this scenario, but events aren't processed.
Is there a way to handle this that is more effective than running my scraping logic on a separate loop and sending notif-send events to the main thread for processing (which will probably be halted by a notification that I hadn't opened)?
Strictly speaking, there is (or can be) one NSRunLoop per thread, not only the main thread. But it's still the case that GUI stuff generally needs to run on the main thread.
I recommend that you take the approach of running scraping on a separate thread. This is generally a good idea for any combination of long-running work and GUI — it ensures that the work cannot cause the UI to hang or hiccup.

when I quit my application, how to ensure ongoing threads are not interrupted at a bad moment?

I'm new to threading, so there are a few things I'm trying to grasp correctly.
I have a windows form application that uses threading to keep my UI responsive while some server shenanigans are going on.
My question is: when I quit my application, what happens to ongoing threads? Will they run to completion or will the abruptly be interrupted?
If they are interrupted, what can I do to make sure they at least don't get interrupted in such a way that would corrupt data on my server (force them to run to a safe place in the code where I know it's ok to interrupt the execution)
You will want to keep a reference of said threads, and call .Abort() on them when you want to terminate. Then you put your thread's code in a try/catch block and handle ThreadAbortException's. This will let you clean up what you are doing and terminate the thread cleanly at your own pace. In the main thread, after you called .Abort(), you just wait until the thread is no longer running (by polling the .IsAlive property of the Thread object) and close your application afterwards.
A thread needs a process to run in. The process won't be able to terminate if you don't terminate all the non-background threads you have started. Threads marked as background thread will be aborted.
So, the behavior is entirely up to your implementation. If you want to close the application, you could wait for all threads to terminate by themself, you could set an event to ask them to terminate and wait or you could just kill the threads.
The UI thread will terminate by itself because it runs a messageloop that stops when requested by the operating system, also see wikipedia and this answer.

Difference between Main Queue / Current Queue & Main Thread / Background Thread in this case?

I'm executing the following method :
MotionHandler.m
-(void)startAccelerationUpdates
{
[motionManagerstartDeviceMotionUpdatesToQueue:[NSOperationQueue mainQueue]withHandler:^(CMDeviceMotion *motion, NSError *error){.....}
}
on a background thread, as follows:
[currentMotionHandler performSelectorInBackground:#selector(startAccelerationUpdates) withObject:nil];
But the above method uses the main Queue (which is on the main thread) to perform the necessary updates even though I'm calling it on a background thread.. So are acceleration updates being performed on a background thread or on the main thread, I'm confused..?
What's even more interesting is that when I call the above method on background thread again, but this time using the current Queue, I get no updates. Could someone please explain the difference between running something on :
1. a background thread but on the main queue
2. a background thread but on the current queue
3. the main thread but on the main queue
4. the main thread but on the current queue
in the current implementation? Thank you!
I'll give it a shot. First, without being told by the NSOperationQueue class reference, we could not infer anything about what thread the 'mainQueue' would run on. Reading it we see that in fact that queue runs its operations on the mainThread, the one the UI uses, so you can update the UI in operations posted to that queue. Although it doesn't say it, these operations must be serial, due to them being executed by the runLoop (its possible they can get preempted too, not 100% sure of that).
The purpose for currentQueue is so that running operations can determine the queue they are on, and so they can potentially queue new operations on that queue.
a background thread but on the main queue
Not possible - the NSOperation's mainQueue is always associated with the mainThread.
a background thread but on the current queue
When you create a NSOperationQueue, and add NSOperations to it, those get run on background threads managed by the queue. Any given operation can query what thread its on, and that thread won't change while it runs. That said, a second operation on that queue may get run on a different thread.
the main thread but on the main queue
See 1)
the main thread but on the current queue
If you queue an operation to the mainQueue (which we know is always on the mainThread), and you ask for the currentQueue, it will return the mainQueue:
[NSOperationQueue currentQueue] == [NSOperationQueue mainQueue];
You are confusing queues with threads. Especially since NSOpertionQueue has been rewritten to use GCD, there is little connection between queues and specific threads (except for the special case of the main thread).
Operations/blocks/tasks - whatever you want to call them - are inserted into a queue, and "worker thread(s)" pull these off and perform them. You have little control over which exact thread is going to do the work -- except for the main queue. Note, this is not exactly right, because it's a simplification, but it's true enough unless you are doing something quite advanced and specific.
So, none of your 4 scenarios even make sense, because you can't, for example, run something on "a background thread but on the main queue."
Now, your method startAccelerationUpdates specifically tells the CMMotionManager to put your handler on the main queue. Thus, when startAccelerationUpdates is called, it gets run in whichever thread it's running, but it schedules the handler to be executed on the main thread.
To somewhat complicate things, you are calling the startAccelerationUpdates method by calling performSelectorInBackground. Again, you don't know which thread is going to actually invoke startAccelerationUpdates, but it will not be the main thread.
However, in your case, all that thread is doing is calling startAccelerationUpdates which is starting motion updates, and telling them to be handled on the main thread (via the main queue).
Now, here's something to dissuade you from using the main queue to handle motion events, directly from the documentation...
Because the processed events might arrive at a high rate, using the main operation queue is not recommended.
Unfortunately, your statement
What's even more interesting is that when I call the above method on
background thread again, but this time using the current Queue, I get
no updates.
does not provide enough information to determine what you tried, how you tried it, or why you think it did not work. So, I'll make a guess... which may be wrong.
I'll key on your use of the current Queue.
I assume you mean that you substitute [NSOperationQueue mainQueue] with [NSOperationQueue currentQueue].
Well, let's see what that does. Instead of using the main queue, you will be using "some other" queue. Which one? Well, let's look at the documentation:
currentQueue
Returns the operation queue that launched the current
operation.
+ (id)currentQueue
Return Value
The operation queue that started the operation or nil if the queue could not be determined.
Discussion
You can use this method from within a running operation
object to get a reference to the operation queue that started it.
Calling this method from outside the context of a running operation
typically results in nil being returned.
Please note the discussion section. If you call this when you are not running an operation that was invoked from an NSOperationQueue, you will get nil which means there will be no queue on which to place your handler. So, you will get nothing.
You must specify which queue is to be used, if you want to use an NSOperationQueue other than the main queue. So, if that's the route you want to go, just create your own operation queue to handle motion events, and be off!
Good Luck!

Triggering via Asynchronous Callbacks

If an application executes a code block asynchronously and notifies the completion state in a callback, do these all leave execution on the main thread (the callback)?
What is the correct way to handle Core Graphics drawing and file operations in this callback?
I currently have these instructions running in the callback, but would like to trigger a thread to handle these instructions instead.
If you are doing any UI drawing, that has to be on the main thread. If you hvae these asynchronous blocks doing work now (ostensibly in a concurrent dispatch queue), why not just do all the work there, and when you have a finished product to show, only then message back on the main block. If your callback calls other methods in your class, the safest way to deal with concurrency is to define helper objects - small objects that take some input and product an output.
Create the helper, attach whatever data it needs, kick it off in a block on a queue, and when its done it messages back on the main thread that extracts the finished product, renders it, then deletes the helper object.
I dont have much experience in Core Graphics, but I've done a good amount of work on blocks.
In my opinion, if your application executes a code block asynchronously (on a new thread), then it's a good practice to the make callback or notification on the main thread.

Saving managed object context creates deadlock in iOS 5's performBlock

I've been looking for a solution for this problem for a long time and have yet reached one.
I'm developing an iOS app with core data. I've created two managed object contexts (MOC) which point to the same persistent store coordinator. One MOC (referred as self.moc) is initiated with main queue concurrency whereas the other mov (referred as self.bmoc) is initiated with private queue concurrency. I've made sure that self.moc only runs on the main thread and self.bmoc only runs within its performBlock or performBlockAndWait block.
However, I've encountered this strange situation where my app freezes on the [self.bmoc save:nil] line. Since the save action is executed within the performBlock block, I don't see a reason for it to reach a deadlock. Since it freezes on that line, I can't receive an error even if I use [self.bmoc save:&error] rather than nil.
Below is the code which will reproduce the problem. Although I have many functions similar to the one below, only this one creates the problem. I fail to figure the cause of the problem and any insight is greatly appreciated. Thank you!
-(void)createEmptyUserData {
[self.bmoc performBlock:^{
User* user = [NSEntityDescription insertNewObjectForEntityForName:#"User" inManagedObjectContext:self.bmoc];
/* sets user object */
[self.bmoc save:nil];
}];
}
Note: This piece of code is executed in main thread.
There are two basic reasons for you to get a "hang" in that situation.
You have a nested call to performBlockAndWait or some other synchronous thread/queue call.
One of your blocks is not returning, and running forever.
Both of these can be easily seen by looking at the stacks of each running thread at the time of the "hang."
performBlock simply takes the execution block and adds it to a queue, then it returns immediately. Some other thread is then popping execution blocks off the queue and executing them.
performBlockAndWait executes in the context of the calling thread. Basically, it waits for currently enqueued execution blocks to run, then it runs the requested code on the current thread.
It des not return until the call is complete.
So, I'd bet you either have multiple nested calls to performBlockAndWait OR one of your asynchronous execution blocks is not completing.
Look at the stack at the time of the hang...
Alternatively, log your block execution, so you can see when each block starts and exits.