Threads that don’t have a runloop - ios

I'm reading Core Animation Programming Guide and in the chapter of "Transactions", I see this
Important: When modifying layer properties from threads that don’t
have a runloop, you must use explicit transactions.
but From Apple's documentation on NSRunLoop
Your application cannot either create or explicitly manage NSRunLoop
objects. Each NSThread object, including the application’s main
thread, has an NSRunLoop object automatically created for it as
needed.
Doesn't it mean every thread has a runloop? or threads that's not created by NSThread, such as POSIX's pthread

It says “Each NSThread object, including the application’s main thread, has an NSRunLoop object automatically created for it as needed.”
If you don't do anything that tries to access a thread's run loop, the system won't create a run loop for the thread.
If you don't do [[NSRunLoop currentRunLoop] run] (or something equivalent), your thread won't run its run loop.
The UIApplicationMain function takes care of this for the main thread. For threads you create, you need to run the thread's run loop if you want the thread's run loop to have any effect.
Here's what's happening (I think) in the case of Core Animation, when you don't use an explicit transaction. It begins a transaction, and registers a callback with the current thread's run loop to commit it. (This will create a run loop for the current thread if necessary.) If you're not running the thread's run loop, that callback will never be called.

Related

Understanding dispatch_queues and synchronous/asynchronous dispatch

I'm an Android engineer trying to port some iOS code that uses 5 SERIAL dispatch queues. I want to make sure I'm thinking about things the right way.
dispatch_sync to a SERIAL queue is basically using the queue as a synchronized queue- only one thread may access it and the block that gets executed can be thought of as a critical region. It happens immediately on the current thread- its the equivalent of
get_semaphore()
queue.pop()
do_block()
release_semaphore()
dispatch_async to a serial queue- performs the block on another thread and lets the current thread return immediately. However since its a serial queue it promises only one of these asynchronous thread is going to execute at a time (the next call to dispatch_async will wait until all other threads are finished). That block can also be thought of as a critical region, but it will occur on another thread. So the same code as above, but its passed to a worker thread first.
Am I off in any of that, or did I figure it out correctly?
This feels like an overly complicated way of thinking of it and there are lots of little details of that description that aren't quite right. Specifically, "it happens immediately on the current thread" is not correct.
First, let's step back: The distinction between dispatch_async and dispatch_sync is merely whether the current thread waits for it or not. But when you dispatch something to a serial queue, you should always imagine that it's running on a separate worker thread of GCD's own choosing. Yes, as an optimization, sometimes dispatch_sync will use the current thread, but you are in no way guaranteed of this fact.
Second, when you discuss dispatch_sync, you say something about it running "immediately". But it's by no means assured to be immediate. If a thread does dispatch_sync to some serial queue, then that thread will block until (a) any block currently running on on that serial queue finish; (b) any other queued blocks for that serial queue run and complete; and (c) obviously, the block that thread A itself dispatched runs and completes.
Now, when you use a serial queue for synchronization for, some thread-safe access to some object in memory, often that synchronization process is very quick, so the waiting thread will generally be blocked for a negligible amount of time as its dispatched block (and any prior dispatched blocks) to finish. But in general, it's misleading to say that it will run immediately. (If it always could run immediately, then you wouldn't need a queue to synchronize access).
Now your question talks about a "critical region", to which I assume you're talking about some bit of code that, in order to ensure thread-safety or for some other reason like that, must be synchronized. So, when running this code to be synchronized, the only question re dispatch_sync vs dispatch_async is whether the current thread must wait. A common pattern, for example, is to say that one may dispatch_async writes to some model (because there's no need to wait for the model to update before proceeding), but dispatch_sync reads from some model (because you obviously don't want to proceed until the read value is returned).
A further optimization of that sync/async pattern is the reader-writer pattern, where concurrent reads are permissible but concurrent writes are not. Thus, you'll use a concurrent queue, dispatch_barrier_async the writes (achieving serial-like behavior for the writes), but dispatch_sync the reads (enjoying concurrent performance with respect to other read operations).
To pick nits, dispatch_sync doesn't necessarily run the code on the current thread, but if it doesn't, it still blocks the current thread until the task completes. The distinction is only potentially important if you're relying on thread IDs or thread-local storage.
But otherwise, yes, unless I missed something subtle.

Clear process flow of NSRunLoop

Digging more than one day....Apple, Google, Slideshare and stackoverflow. But still not clear about NSRunLoop.
Every thread has a runloop by default.Application mainThread has mainRunLoop.
1. If MainRunLoop get input events is it creating new thread to execute it? Then another runLoop created? How then multiple thread and multiple runLoop work? Communicate?
2. If runLoop has no input event/task it sleeps.When a RunLoop ends?
3. Why i should care about runLoop?
4. Where i can use it?
Where i miss that i can't understand the life cycle?
Lets look on your`s list:
Wrong. Threads do not have built-in runloop. They need to be created manually.
Runloop doesn`t create another threads, its immediately executes an event. That is why at the main thread we can see locked interface - by heavy-load tasks in the main thread (UI in iPhone runs on the main thread). Runloops can communicate with each other with the help of mac ports.
Runloop sleeps before the first event come, then wakes up and ends. Only exception - timer, but it will not runloop. Runloop need to start run every time after Event (in the loop). If you call the run, there is already a built-in loop.
Can use to create some threads which must track or execute something periodically. For example, you can create a thread, when runloop for it and then other threads can execute it`s selectors through performSelector. This creates a background query processor, which does not require each time to create a new thread.

How do i schedule something in the runloop of another thread?

I am writing an application that is going to send/receive data over tcp connections and I wanted to schedule the read/write to happen in the run loop of a different thread. Meaning Thread 1 is creating the connection and scheduling it on the run loop of Thread 2. I am unable to find any way of accessing the run loop of a different thread so I wrote a piece of code that the secondary thread will run which will store its run loop in a globally accessible location. I wanted to know if this is the right way to do it or if there is any other/better way to do the same and also if the way I have done it will cause problems like access to the run loop not being thread safe and causing issues if i attempt to schedule multiple things on the run loop of the same thread from multiple threads.
Something like the following.
[NSRunLoop currentRunLoop] --> This I can do from the thread whose runloop I want to access
NSRunLoop * secondthreadrunloop = [secondthread getRunLoop]; -->But is there anything like this?
I encountered the same problem recently and it seems that the answer is - no, you cannot schedule anything on a NSRunLoop running on a different thread. Apple says that NSRunLoop is not thread safe which means that attaching an NSTimer instance to it would result in an undefined behaviour (I have checked it, in my case it randomly generates crashes).
What can be done though is to schedule a repeating timer from the background thread itself and make it pick up the work you want it to do from some atomic property.

What is the difference between dispatch_sync and dispatch_main?

I understand that dispatch_async() runs something on a background thread, and dispatch_main() runs it on the main thread, so where does dispatch_sync() come in?
You don't generally want to use dispatch_main(). It's for things other than regular applications (system daemons and such). It is, in fact, guaranteed to break your program if you call it in a regular app.
dispatch_sync runs a block on a queue and waits for it to finish, dispatch_async runs a block on a queue and doesn't wait for it to finish.
Serial queues run one block at a time, in order. Concurrent queues run multiple blocks at a time, and therefore aren't necessarily in order.
(edit)
Perhaps when you said dispatch_main() you were thinking of dispatch_get_main_queue()?
dispatch_main() is not for running things on the main thread — it runs the GCD block dispatcher. In a normal app, you won't need or want to use it.
dispatch_sync() blocks the current thread until the block completes. This may or may not be the main thread.
If you want to run something on the main thread, you can use dispatch_get_main_queue() to get the main queue and use once of the normal dispatch methods to run a block there.

NSOperationQueue, concurrent operation and thread

I'm developing a sort of fast image scan application.
In the -captureOutput:didOutputSampleBuffer:fromConnection: method I pick up the CVPixelBuffer and add them into an NSOperation subclass. The NSOperation takes the buffer and transform it into an image saved on the filesystem.
The -isConcurrent method of NSOperation returns YES. After the operation is created, is added to an NSOperationQueue.
Everything runs fine except for one issue that is affecting the scan frame rate.
Using time profiler I've found that some of the NSOperation are run on the same thread of the AVCaputureVideoOutput delegate that I've created:
dispatch_queue_t queue = dispatch_queue_create("it.CloudInTouchLabs.avsession", DISPATCH_QUEUE_SERIAL);
[dataOutput setSampleBufferDelegate:(id)self queue:queue];
When an operation is running on the same thread of the AV session queue, it affects the frame rate, it happens only with some them, probably GCD is deciding under the hood dispatching on active threads. The only method I've found to solve that issue, is to create a separate thread and pass it to the the single operations forcing them to run on it.
Is there another way, to force operations run on a different thread?
[EDIT]
Following the #impcc suggestions I made some test.
Results are pretty interesting even if sort of inconsistent.
Test platform is an iPhone 5 connected in debugging mode through an MBP with 16gb of RAM quad core i7. The session has a 60fps output tested with the algorithm in RosyWriter apple sample code.
AVSession queue sync targeted to high priority queue
26 fps where sometimes the thread of the queue is shared with the one
of the operation. The time taken inside the delegate methods has an
average of 0.02s
14 fps with a thread created just for the operations, if the main
method is not called on this thread, the start will be forced to perform
on that specific thread. This thread is create one time and kept
alive with a dummy port.. The time taken inside the delegate is
0.008.
AVSession queue concurrent targeted to high priority queue
13.5 fps where sometimes the thread of the queue is shared with the one of the operation. The time taken inside the delegate methods has
an average of 0.02s, substacially equal to the counterpart with sync
queue.
14 fps with a thread created just for the operations, if the main
method is not called on this thread, the start will be forced to perform
on that specific thread. This thread is create one time and kept
alive with a dummy port. The time taken inside the delegate is
0.008.
Conclusion
Concurrent or serial queue doesn't seems to make a big difference, however concurrent for me is not ok cause of the timestamps that I need to take to preserve the sequence of single picture. The fact that is surprising me is the frame drop using an ad-hoc thread, even if the time taken inside the delegate method is considerably less, the frame rate drops about 10fps. Just trusting in GCD the frame rate is better but the delegate methods takes more than 2 times to finish, this probably due to the fact that sometimes the AV queue is used by also the nsoperations. I can't really get why the time taken inside the delegate doesn't seems to be correlated to the fps. Shouldn't be the faster the better?
By further investigations it really seems that what is stealing time si in the process of adding and probably executing operation in queue.
I think you might be misunderstanding the meaning of isConcurrent. This is totally understandable, since it's incredibly poorly named. When you return YES from -isConcurrent what it really means is "I will handle any concurrency needs associated with this operation, and will otherwise behave asynchronously." In this situation, NSOperationQueue is free to call -start on your operation synchronously on the thread from which you add the operation. The NSOperationQueue is expecting that, because you've declared that you will manage your own concurrency, that your -start method will simply kick off an asynchronous process and return right away. I suspect this is the source of your problem.
If you implemented your operation by overriding -main then you almost certainly want to be returning NO from isConcurrent. To make matters more complicated, the behaviors associated with isConcurrent have changed over the years (but all that is covered in the official docs.) A fantastic explanation of how to properly implement a returns-YES-from-isConcurrent NSOperation can be found here.
The way I'm reading your question here, it doesn't sound like your NSOperation subclass actually needs to "manage its own concurrency", but rather that you simply want it to execute asynchronously, "on a background thread", potentially "concurrently" with other operations.
In terms of assuring the best performance for your AVCaptureVideoDataOutputSampleBufferDelegate callbacks, I would suggest making the queue you pass in to -setSampleBufferDelegate:queue: be (itself) concurrent and that it target the high-priority global concurrent queue, like this:
dispatch_queue_t queue = dispatch_queue_create("it.CloudInTouchLabs.avsession", DISPATCH_QUEUE_CONCURRENT);
dispatch_set_target_queue(queue, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0));
[dataOutput setSampleBufferDelegate:(id)self queue:queue];
Then you should make the delegate callback methods as lightweight as possible -- nothing more than packaging up the information you need to make the NSOperation and add it to the NSOperationQueue.
This should ensure that the callbacks always take precedence over the NSOperations. (It's my understanding that NSOperationQueue targets either the main queue (for the NSOperationQueue that's associated with the main thread and run loop) or the default priority background queue.) This should allow your callbacks to fully keep up with the frame rate.
Another important thing to take away here (that another commenter was getting at) is that if you're doing all your concurrency using GCD, then there is only one special thread -- the main thread. Other than that, threads are just a generic resource that GCD can (and will) use interchangeably with one another. The fact that a thread with a thread ID of X was used at one point to service your delegate callback, and at another point was used to do your processing is not, in and of itself, indicative of a problem.
Hope this helps!

Resources