Let’s practice multithreading

Daniil Vorobyev
4 min readMay 12, 2019

--

Hi all Medium community. In this article I would like to show by examples how multithreading works in Swift. I know that there are many articles on the topic of multithreading in iOS, but I would like to systematize all the basic points here. So, let’s start.

Firstly, should clarify what thread and queue are:

  • Thread is a point of execution in program, that executes a process in the system.
  • Queue is a different from the thread. They are merely queues of closures that will eventually be forwarded to a relevant thread by the system.

Note, that processor can perform only one of your tasks at any given time, and in the case of a single-core CPU multithreading is achieved by fast switching between threads (context switch). In the case of multiply-core CPU multithreading is achieved by the fact that each thread associated with a task is provided with its own core for running tasks.

A queue can be synchronous and asynchronous:

  • Sync function locks the current queue, and returns control to the current queue only after completing its task
  • Async function returns control to the current queue immediately after starting the job for execution in another queue, without waiting for it to complete

Enough of boring theory, now let’s create two test functions with emoji printing and two queues.

And let’s see what the next piece of code displays:

Output

Here sync function of queue1 stops the execution of our current main queue and returns to it only after completing emoji1(). And only then system takes the queue2 closure into processing and performs emoji2().

Now consider another example:

Here we see a resource-intensive addition operation that is performed in a cycle, as well as an asynchronous print(“1”) call in the same queue first. Let’s see the program output:

Output

As we can see, queue1.async { print(“1”) } didn’t execute before resource-intensive operation. The reason is simple: Queue1 is a serial queue.

  • Serial queue is a queue which sequentially executes its closures
  • Concurrent queue is a queue which executes its closures in parallel, without waiting for the execution of the current task.
Concurrent and serial queues

Note: DispatchQueue.main is a serial queue

So in the example above, print(“1”) will be executed only after the external process is completed.

Finally, let’s look at the last example:

and its output:

output
  • Obviously ( I hope so :) ), the first will be called print(“1”)
  • Next will be called print(“4”). Why so? Even despite the presence of sleep(2), queue1 is a serial queue, which means the system can’t start executing other queue1 blocks, and also can’t continue to perform queue2, because queue1.sync { sleep(1) … } blocked further execution of queue2
  • Next will be called print(“5”) because closure with print(“5”) was added in the queue earlier than print(“2”)
  • Then print(“6”) will be called. Obviously that a synchronous call of queue1.sync { print(“5”)} blocked print(“6”) execution.
  • Only after queue1 has completed the previous blocks — print(“2”) called
  • The last print that we see — print(“3”)

But if we make our queue1 concurrent

we will see a completely different result:

Result with concurrent queue1

Now those functions sleep() directly affect the order of execution of the code since the concurrent queue1 begins to execute closures without waiting for the completion of the previous.

Multithreading is a very important and interesting mechanism that includes a lot of hard and easy things. I didn’t have time to tell in this article about such things as Quality of Service, Semaphores, DispatchWorkItem, OperationQueue and many others the iOS developer should be aware of. If this article is useful I will definitely continue a series of topics about multithreading. I will be glad to hear about any comments on the content of the article. Thanks for reading and good luck :)

--

--