Concurrency is important in iOS apps, you should use concurrent api when you want some tasks running parallelly, or you want to do task in background thread in order not to block your UI thread. IOS provides us several kinds of concurrent api, like Thread, Grand central dispatch (GCD) and NSOperationQueue. Instead of using NSThread, we should always choose GCD or NSOperationQueue, for GCD and NSOperationQueue, OS will optimize the number of threads according to current state of the System. If there are already enough threads in the system, OS can decrease parallel threads managed in the thread pool of GCD and NSOperationQueue and avoid extra threads taking too much memory. In my recent work, I solved some concurrent programming issue, and want to summize my knowledge about GCD and NSOperationQueue, I also wrote an simple project, which demostrate basic usage of these concurrent api, you can downlaod the project source code for detail.
Dispatch Queue is very convinent to use, and ios exposes five different kinds of dispatch queues:three background queue with different priorities(low, normal, high),which are all concurrent queue, main queue running on main thread, and one background queue used for I/O operation. You can also create your own serial queue or concurrent queue as you needed.
Dispatch Queue
If you need to perform some task on background queue, it recommended to use system provided queues. With the api below dispatch_queue_t dispatch_get_global_queue(
long priority,
unsigned long flags)
If you want to create queue yourself, you can use dispatch_queue_create
and pass one string to label this queue, and DISPATCH_QUEUE_CONCURRENT
or DISPATCH_QUEUE_SERIAL
to indicate the type of this queue.
After get the handle of the queue, you need to add your block to this queue withdispatch_async
or dispatch_sync
method, and then your block will start run at a proper time managed by the system.
After we add blocks to the queue, we have no control over the block any more, there is no api for you to cancel the operation in the queue or to the state of the operation in the queue(If you want these, you may refer to NSOperationQueue, which will be introduced in next article).
#####Resource protection for multiple thread
Because of the concurrency of blocks in dispatch queue, we need to protect our resource if it is written in the blocks, and dispatch_barrier_async
is a good helper. Look at the code below:1
2
3
4
5
6
7
8dispatch_queue_t queue = dispatch_queue_create("concurrentQueue", DISPATCH_QUEUE_CONCURRENT);
//if we want to add an item to array
- (void)insertString:(NSString*)str
{
dispatch_barrier_async(queue, ^{
[self.array addObject:str];
});
}
With the code above, all insert operation is safe, below the addObject block will be executed when all blocks in the queue before it are completed.(Maybe this example is meaningless, it’s just a example).
Dispatch Group
Sometimes we may want to do paralle tasks in dispatch queue, and we need to integrate results from different blocks, that is we want to do some operaton when all blocks we submitted to a queue are completed. In this situation, dispatch groups can help.1
2
3
4
5
6
7
8
9
10
11
12
13
14dispatch_group_t group = dispatch_group_create();
dispatch_queue_t queue = dispatch_get_global_queue(0,0);
dispatch_group_async(group, queue, ^{
//some operation
});
dispatch_group_async(group, queue, ^{
//some other operations
});
//perform some task when all operations are done
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
NSLog(@"All blocks in this group are done");
})group
are completed.
There are also some other detail techniqual point about GCD, if you are interested you can refer to this guide for detail.
Hope this will be helpful :)