Are threads shared between different Dispatch queues? - ios

Can a single thread be used in different dispatch queues?
I'm developing an app where i want to get a value depending on the thread where the code is running. For that i change the name of the thread when the block starts in a custom queue.
For example, if I add a block to mi custom queue, and i change the name of that thread to "SyncThread". Does a block called in a default system queue will be executed in that "SyncThread"?

Can a single thread be used in different dispatch queues?
Yes, and this is common. (The concept of "different dispatch queues" is itself problematic, since queues can, and do, target other queues. Seemingly simple questions like "what is the current queue" are not well defined.)
I'm developing an app where i want to get a value depending on the thread where the code is running. For that i change the name of the thread when the block starts in a custom queue.
What you likely want for this is queue contextual data rather than thread-specific data (usually called thread-local storage). See DispatchQueue.setSpecific(key:value:).

You use the terms thread and queue interchangeably but they aren't interchangeable; they're two distinct things. Apple doesn't want developers threading anymore, they want developers queueing their tasks. The queueing is handled by GCD which does all the threading behind the scenes. This means that two queues can certainly run on the same thread. And while all tasks within a queue run on distinct threads, not every task is guaranteed to run on the same thread, so keep that in mind. Therefore, I would take the advice given here to focus instead on queue context, not thread context.

Related

How to make sure that OperationQueue tasks are always getting executed on background(global) thread in swift?

I encountered a problem with non-iOS developer while describing the flow of OperationQueue. We already know that with OperationQueue we can start as many threads as we want to execute the tasks in sync/async way.
But in practical, some of the people want proof for the OperationQueue is getting executed in the background and not with UI(Main) thread.
I just want to demonstrate that when operation queue starts, it already starts its execution in the background.
I already have convinced that when we try to set qos for the operationQueue that we create, it has all the parameters of global queue's qos viz: default userInitiated userInteractive background and utility.
So that is already perfect example in code to prove that all the OperationQueue operations mentioned are run on global thread. Unless we declare the OperationQueue.main
As Shadowrun said, you can add assertions for Thread.isMainThread. Also, if you ever want to add test that you are not on the main queue, you can add a precondition:
dispatchPrecondition(.notOnQueue(.main))
But it should be noted that the whole purpose of creating an operation queue is to get things off the main thread. E.g., the old Concurrency Programming Guide: Operation Queues says [emphasis added]:
Operations are designed to help you improve the level of concurrency in your application. Operations are also a good way to organize and encapsulate your application’s behavior into simple discrete chunks. Instead of running some bit of code on your application’s main thread, you can submit one or more operation objects to a queue and let the corresponding work be performed asynchronously on one or more separate threads.
This is not to say that operation queues cannot contribute to main thread responsiveness problems. You can wait from the main thread for operations added to an operation queue (which is obviously a very bad idea). Or, if you neglect to set a reasonable maxConcurrentOperationCount and have thread explosion, that can introduce all sorts of unexpected behaviors. Or you can entangle the main thread with operation queues through a misuse of semaphores or dispatch groups.
But operations on an operation queue (other than OperationQueue.main) simply do not run on the main thread. Technically, you could get yourself in trouble if you started messing with the target queue of the underlying queue, but I can’t possibly imagine that you are doing that. If you are having main thread problems, your problem undoubtedly rests elsewhere.

GCD: does thread only has two types? main thread and background thread

Context:
From my understanding, the Main DispatchQueue only dispatch tasks on Main Thread which is for UI mostly.
However the Main Thread can also be used by non-main DispatchQueues.
Apple has QOS to priorities the tasks:
User Interactive: Work that happens on the main thread, such as animations or drawing operations.
User Initiated: Work that the user kicks off and should yield immediate results. This work must be completed for the user to continue.
Utility: Work that may take a bit and doesn’t need to finish right away. Analogous to progress bars and importing data.
Background: This work isn’t visible to the user. Backups, syncs, indexing, etc.
My Question Is:
0, as title described, does thread only contain 2 types, which are Main Thread and Background Thread?
1, does Background Thread mean that all the tasks executed won't block the UI ?
2, Since it mentions that the User Interactive is the priority that the task will be executed on the main thread to avoid UI lags, does it mean all other types: User Initiated, Utility, Background will make sure to have Background Thread that does not block UI?
3, From the link, How to create dispatch queue in Swift 3.
It mentions a couple of different ways to create a Dispatch Queue, some are concurrent, some are serial. It also mentions that by assigning QOS with default or background, it guarantees that the Queue accesses to background threads. But nothing like this mentioned in the Serial and Concurrent. I wonder are those correct?
You ask:
does thread only contain 2 types, which are Main Thread and Background Thread?
I’m not sure if I’d describe them as different “types”, but from the application developer’s perspective, yes, there is the “main” thread, dedicated to the UI, the main run loop, etc., and there are all other threads, which are, in contrast and by definition, “background” threads.
We always want to be careful as to what we run the main queue (i.e. don’t run anything on it that could block that thread and effectively block the UI). In practice, we want to avoid doing anything on the main queue that could block it for more than a few milliseconds, at most.
does Background Thread mean that all the tasks executed won't block the UI?
Effectively, yes. But we’re dealing with limited resources on our devices and therefore the developers must be judicious. For example, for our background tasks, we want to use a QoS that is commensurate for what that queue is doing. Or if parallelizing some task, one should be careful about constraining the degree of concurrency. But if one is judicious about the use of system resources, and keep blocking tasks off the main queue, then that can ensure a responsive UI.
Bottom line, yes, if you have some code that would block the thread on which its run (e.g. it’s computationally expensive, it has blocking calls like semaphores or dispatch group wait, etc.), you would generally run that on a background thread to avoid blocking the main queue.
Since it mentions that the User Interactive is the priority that the task will be executed on the main thread to avoid UI lags, does it mean all other types: User Initiated, Utility, Background will make sure to have Background Thread that does not block UI?
These are just “quality of service” levels, which are just relative priorities for queues. It’s not a question of “block the UI” or “not”, but rather just a matter of how GCD prioritizes and allocates resources.
From the link, How to create dispatch queue in Swift 3. It mentions a couple of different ways to create a Dispatch Queue, some are concurrent, some are serial...
Yes
... It also mentions that by assigning QOS with default or background, it guarantees that the Queue accesses to background threads...
This doesn’t quite make sense. Perhaps you can share the specific excerpt from the docs and we can help you interpret what they were trying to say.
... But nothing like this mentioned in the Serial and Concurrent. I wonder are those correct?
The QoS is just a question of priority and resources for a given queue. Serial vs concurrent is just a question of whether a queue is limited to a single thread at a time, or whether it can avail itself of multiple threads when needed and available.

Confusing with technical terminology between Thread and Queue

I am newer to iPhone development. With focusing on develop multi-threading Apps, I have referred to some Apple documents and others explaining thread and multi-threading concepts. But as far as work-queue is concerned, I am confused in understanding relation between Thread, Task and Queue. Some documents says, a thread can have multiple tasks and those tasks is stored in queue, thus each thread may have its own queue. Whereas, some says that, threads themselves are stored in queue.
My question is, can we say:
(1) Threads can have multiple Tasks and those task are stored and managed inside a Queue of that thread.
OR
(2) Threads themselves are stored and managed inside a Queue.
Secondly, I also read something like this:
Another advantage of using a thread pool over creating a new thread for each task is thread creation and destruction overhead is negated.
Is thread pool synonym for work-queue?
I am clear now.
Thread and queue is totally different things. Thread is separate code of execution while queue is data structure for maintaining tasks. A thread can have multiple tasks and all threads may be created for particular goal that is Process. A thread has its own space in memory for its variables and other things.
So, in multi-threading programming, queue is a mechanism that handle sequence of tasks to be executed. Queue always executes tasks in serial order. However, if we want to execute tasks concurrently, we would have to create concurrent queues. Thus multiple queues can executed concurrently benefiting multiprogramming. With latest API, it is upto operating system that how to schedule those tasks. Tasks may or may not be executed on separate thread. Structure always depends on our requirement.

If I want a task to run in the background, how does the "dispatch_get_global_queue" queue work?

When selecting which queue to run dispatch_async on, dispatch_get_global_queue is mentioned a lot. Is this one special background queue that delegates tasks to a certain thread? Is it almost a singleton?
So if I use that queue always for my dispatch_async calls, will that queue get full and have to wait for things to finish before another one can start, or can it assign other tasks to different threads?
I guess I'm a little confused because when I'm choosing the queue for an NSOperation, I can choose the queue for the main thread with [NSOperationQueue mainQueue], which seems synonymous to dispatch_get_main_queue but I was under the impression background queues for NSOperation had to be individually made instances of NSOperationQueue, yet GCD has a singleton for a background queue? (dispatch_get_global_queue)
Furthermore - silly question but wanted to make sure - if I put a task in a queue, the queue is assigned to one thread, right? If the task is big enough it won't split it up over multiple threads, will it?
When selecting which queue to run dispatch_async on,
dispatch_get_global_queue is mentioned a lot. Is this one special
background queue that delegates tasks to a certain thread?
A certain thread? No. dispatch_get_global_queue retrieves for you a global queue of the requested relative priority. All queues returned by dispatch_get_global_queue are concurrent, and may, at the system's discretion, dispatch work to many different threads. The mechanics of this are an implementation detail that is opaque to you as a consumer of the API.
In practice, and at the risk of oversimplifying it, there is one global queue for each priority level, and at the time of this writing, based on my experience, each of those will at any given time be dispatching work to between 0 and 64 threads.
Is it almost a singleton?
Strictly no, but you can think of them as singletons where there is one singleton per priority level.
So if I use that queue always for my dispatch_async calls, will that
queue get full and have to wait for things to finish before another
one can start, or can it assign other tasks to different threads?
It can get full. Practically speaking, if you are saturating one of the global concurrent queues (i.e. more than 64 background tasks of the same priority in flight at the same time), you probably have a bad design. (See this answer for more details on queue width limits)
I guess I'm a little confused because when I'm choosing the queue for
an NSOperation, I can choose the queue for the main thread with
[NSOperationQueue mainQueue], which seems synonymous to
dispatch_get_main_queue
They are not strictly synonymous. Although NSOperationQueue uses GCD under the hood, there are some important differences. For instance, in a single pass of the main run loop, only one operation enqueued to +[NSOperationQueue mainQueue] will be executed, whereas more than one block submitted to dispatch_get_main_queue might be executed on a single run loop pass. This probably doesn't matter to you, but they are not, strictly speaking, the same thing.
but I was under the impression background
queues for NSOperation had to be individually made instances of
NSOperationQueue, yet GCD has a singleton for a background queue?
(dispatch_get_global_queue)
In short, yes. It sounds like you're conflating GCD and NSOperationQueue. NSOperationQueue is not just a "trivial wrapper" around GCD, it's its own thing. The fact that it's implemented on top of GCD should not really matter to you. NSOperationQueue is a task queue, with an explicitly settable width, that you can create instances of "at will." You can make as many of them as you like. At some point, all instances of NSOperationQueue are, when executing NSOperations, pulling resources from the same pool of system resources as the rest of your process, including GCD, so yes, there are some interactions there, but they are opaque to you.
Furthermore - silly question but wanted to make sure - if I put a task
in a queue, the queue is assigned to one thread, right? If the task is
big enough it won't split it up over multiple threads, will it?
A single task can only ever be executed on a single thread. There's not some magical way that the system would have to "split" a monolithic task into subtasks. That's your job. With regard to your specific wording, the queue isn't "assigned to one thread", the task is. The next task from the queue to be executed might be executed on a completely different thread.

What is the difference between dispatch_get_global_queue and dispatch_queue_create?

I'm writing a moderately complex iOS program that needs to have multiple threads for some of its longer operations (parsing, connections to the network...etc). However, I'm confused as to what the difference is between dispatch_get_global_queue and dispatch_queue_create.
Which one should I use and could you give me a simple explanation of what the difference is in general? Thanks.
As the documentation describes, a global queue is good for concurrent tasks (i.e. you're going to dispatch various tasks asynchronously and you're perfectly happy if they run concurrently) and if you don't want to encounter the theoretical overhead of creating and destroying your own queue.
The creating of your own queue is very useful if you need a serial queue (i.e. you need the dispatched blocks to be executed one at a time). This can be useful in many scenarios, such as when each task is dependent upon the preceding one or when coordinating interaction with some shared resource from multiple threads.
Less common, but you will also want to create your own queue if you need to use barriers in conjunction with a concurrent queue. In that scenario, create a concurrent queue (i.e. dispatch_queue_create with the DISPATCH_QUEUE_CONCURRENT option) and use the barriers in conjunction with that queue. You should never use barriers on global queues.
My general counsel is if you need a serial queue (or need to use barriers), then create a queue. If you don't, go ahead and use the global queue and bypass the overhead of creating your own.
If you want a concurrent queue, but want to control how many operations can run concurrently, you can also consider using NSOperationQueue which has a maxConcurrentOperationCount property. This can be useful when doing network operations and you don't want too many concurrent requests being submitted to your server.
Just posted in a different answer, but here is something I wrote quite a while back:
The best way to conceptualize queues is to first realize that at the very low-level, there are only two types of queues: serial and concurrent.
Serial queues are monogamous, but uncommitted. If you give a bunch of tasks to each serial queue, it will run them one at a time, using only one thread at a time. The uncommitted aspect is that serial queues may switch to a different thread between tasks. Serial queues always wait for a task to finish before going to the next one. Thus tasks are completed in FIFO order. You can make as many serial queues as you need with dispatch_queue_create.
The main queue is a special serial queue. Unlike other serial queues, which are uncommitted, in that they are "dating" many threads but only one at time, the main queue is "married" to the main thread and all tasks are performed on it. Jobs on the main queue need to behave nicely with the runloop so that small operations don't block the UI and other important bits. Like all serial queues, tasks are completed in FIFO order.
If serial queues are monogamous, then concurrent queues are promiscuous. They will submit tasks to any available thread or even make new threads depending on system load. They may perform multiple tasks simultaneously on different threads. It's important that tasks submitted to the global queue are thread-safe and minimize side-effects. Tasks are submitted for execution in FIFO order, but order of completion is not guaranteed. As of this writing, there are only three concurrent queues and you can't make them, you can only fetch them with dispatch_get_global_queue.
edit: blog post expanding on this answer: http://amattn.com/p/grand_central_dispatch_gcd_summary_syntax_best_practices.html
One returns the existing global queue, the other creates a new one. Instead of using GCD, I would consider using NSOperation and operation queue. You can find more information about it in this guide. Typically, of you want the operations to execute concurrently, you want to create your own queue and put your operations in it.

Resources