iOS Concurrent Programming:GCD

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 with
dispatch_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
8
dispatch_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
14
dispatch_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");
})
In this case, the block in the dispatch_group_notify will be executed only after all operations in 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 :)