Concurrency in Swift (Grand Central Dispatch Part 2)

https://www.raywenderlich.com/5370-grand-central-dispatch-tutorial-for-swift-4-part-1-2

In this part we will cover following topics

  1. What is Dispatch Group
  2. How to implement Dispatch Group Using wait and notify strategy
  3. What is Dispatch Barrier
  4. How to solve reader-writer problem using Dispatch Barrier

This is the continuation of the previous part . If you know the basics of GCD you can continue this.

Dispatch Group

  1. Dispatch groups are a way to block a thread until one or more tasks finish executing. You can use this behavior in places where you cannot make progress until all of the specified tasks are completed.
  2. After dispatching several tasks to compute some data, you might use a group to wait on those tasks and then process the results when they are done though they might run on different queues as well..
  3. DispatchGroup allows for aggregate synchronization of work

As shown in Figure 1 we executed two tasks concurrently and wait for them to finished by using wait function on dispatch group which will block the thread until both of these tasks will execute. These are the following steps performed by the below code

Dispatch Group Using wait

  1. Created a concurrent custom queue with label “com.company.app.queue”
  2. Created a dispatch group
  3. Manually indicate a block has entered the group using group.enter() Note: Calls to this function must be balanced with dispatch_group_leave() otherwise application will crash
  4. Executed task 1 through queue.async which will return immediately and GCD will start run this task concurrently
  5. Manually indicate a block has entered the group using group.enter()
  6. Executed task 2 through queue.async which will return immediately and GCD will start run this task concurrently
  7. group.wait() (will block whatever thread we are on here until all the above tasks have finished (so don't use this function on your main thread) since we called this method on main thread it will block the main thread. group.wait() waited until both these tasks will finished
Figure 1

As shown in Figure 2 now we are now blocking background thread since we are using wait() method on concurrent queue instead of main queue.

Figure 2

Dispatch Group Using notify

Dispatching asynchronously to queue then blocking work using wait is not looking good as you can see from previous example we block the main thread. Fortunately, there is a better way. DispatchGroup can instead notify you when all the group’s tasks are complete. As shown in Figure 3 when both tasks completed dispatch group will invoke notify method where you can write your completion logic

Figure 3

As shown in Figure 3.1 and 3.2 we used notify but “#3 finished” is printed after task1 and task 3 is finished but it didn’t wait for task2 and it’s because you didn’t add task2 on the group so it will not wait for this task to complete.

Groups allow you to aggregate a set of tasks and synchronize behaviors on the group. You attach multiple work items to a group and schedule them for asynchronous execution on the same queue or different queues. When all work items finish executing, the group executes its completion handle

Figure 3.1
Figure 3.2

As shown in Figure 3.3 now group will wait until all three tasks will finished since we added enter() and leave() now group will look this task as well

Figure 3.3

Dispatch group takes queue as a parameter which decide in which queue our completion block will execute. As shown in Figure 3.4 since we specify Dispatch.main() “#3 finished” will print on main thread

Figure 3.4

Dispatch Barrier

  1. Dispatch barriers are a group of functions acting as a serial-style bottleneck when working with concurrent queues.
  2. When you submit a DispatchWorkItem(task ) to a dispatch queue you can set flags to indicate that it should be the only item executed on the specified queue for that particular time. This means that all items submitted to the queue prior to the dispatch barrier task must complete before it start execute barrier task.

As shown in Figure 4 we performed following steps

  1. Created a custom concurrent dispatch queue
  2. Added first and second task async on the queue. See part 1 if you don’t understand it
  3. At that time two tasks added to the concurrent queue and both are running concurrently. Now we if add third task as a dispatch barrier it will not start until and unless both of the previous tasks completed its execution and when it start it will execute barrier task serially (means GCD will only execute this task on this queue until it completed that task).
  4. Finally we added four task which will not execute until and unless barrier task will complete.
Figure 4

As shown in Figure 5 barrier task execute in an isolation serially though it’s a concurrent queue since task 4 added after barrier it executed after barrier task finished.

Figure 5

As shown in figure 6 created a rough diagram how dispatch barrier works

Figure 6

Read Writer Problem Solution Using Barrier

If you are doing read and write operation from multiple threads in a concurrent queue you will encounter reader-writer problem. See this link for the solution where write operation task was put as a barrier which will ensure it will execute serially and read operation execute as a normal task which can run concurrently. When write operation starts no read operation will perform.

In computer science, the readers-writers problems are examples of a common computing problem in concurrency. There are at least three variations of the problems, which deal with situations in which many threads (small processes which share data) try to access the same shared resource at one time

Useful Links

https://www.appcoda.com/grand-central-dispatch/

Next

In the next part we will discuss Operations and Operation Queue

Senior iOS Engineer | HungerStation | Delivery Hero