Repository navigation
Expand file tree
/
Copy pathunderstanding-dispatchqueues.html
More file actions
445 lines (402 loc) · 29.2 KB
/
Copy pathunderstanding-dispatchqueues.html
File metadata and controls
445 lines (402 loc) · 29.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
<!DOCTYPE html>
<html lang="en">
<head>
<script src="https://use.fontawesome.com/afd448ce82.js"></script>
<!-- Meta Tag -->
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<!-- SEO -->
<meta name="author" content="Bruno Rocha">
<meta name="keywords" content="Software, Engineering, Blog, Posts, iOS, Xcode, Swift, Articles, Tutorials, OBJ-C, Objective-C, Apple">
<meta name="description" content="Multithreading in general is a difficult thing to fully understand, but understanding how the CPU deals with concurrency is the key to writing good, fast code that does what you expected it to do. Otherwise, you might be abusing your user's CPUs but thinking everything is fine because they are too fast for you to notice that something is wrong.">
<meta name="title" content="Understanding DispatchQueues">
<meta name="url" content="https://swiftrocks.com/understanding-dispatchqueues">
<meta name="image" content="https://swiftrocks.com/images/thumbs/thumb_dark.jpg">
<meta name="copyright" content="Bruno Rocha">
<meta name="robots" content="index,follow">
<meta property="og:title" content="Understanding DispatchQueues"/>
<meta property="og:image" content="https://swiftrocks.com/images/thumbs/thumb_dark.jpg"/>
<meta property="og:description" content="Multithreading in general is a difficult thing to fully understand, but understanding how the CPU deals with concurrency is the key to writing good, fast code that does what you expected it to do. Otherwise, you might be abusing your user's CPUs but thinking everything is fine because they are too fast for you to notice that something is wrong."/>
<meta property="og:type" content="website"/>
<meta property="og:url" content="https://swiftrocks.com/understanding-dispatchqueues"/>
<meta name="twitter:card" content="summary_large_image"/>
<meta name="twitter:image" content="https://swiftrocks.com/images/thumbs/thumb_dark.jpg"/>
<meta name="twitter:image:alt" content="Page Thumbnail"/>
<meta name="twitter:title" content="Understanding DispatchQueues"/>
<meta name="twitter:description" content="Multithreading in general is a difficult thing to fully understand, but understanding how the CPU deals with concurrency is the key to writing good, fast code that does what you expected it to do. Otherwise, you might be abusing your user's CPUs but thinking everything is fine because they are too fast for you to notice that something is wrong."/>
<meta name="twitter:site" content="@rockbruno_"/>
<meta name="fediverse:creator" content="@rockbruno@hachyderm.io">
<!-- Favicon -->
<!-- 16x16 -->
<link rel="shortcut icon" href="images/favicon/favicon.ico" type="image/x-icon">
<link rel="apple-touch-icon" href="images/favicon/favicon_180.png" sizes="180x180">
<link rel="icon" href="images/favicon/favicon_32.png" sizes="32x32" type="image/png">
<link rel="icon" href="images/favicon/favicon_48.png" sizes="48x48" type="image/png">
<link rel="icon" href="images/favicon/favicon_96.png" sizes="96x96" type="image/png">
<link rel="icon" href="images/favicon/favicon_144.png" sizes="144x144" type="image/png">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Source+Sans+3:ital,wght@0,200..900;1,200..900&display=swap" rel="stylesheet">
<link rel="canonical" href="https://swiftrocks.com/understanding-dispatchqueues"/>
<!-- Bootstrap CSS Plugins -->
<link rel="stylesheet" type="text/css" href="css/bootstrap.css">
<!-- Prism CSS Stylesheet -->
<link rel="stylesheet" type="text/css" href="css/prism5.css">
<!-- Main CSS Stylesheet -->
<link rel="stylesheet" type="text/css" href="css/style49.css">
<link rel="stylesheet" type="text/css" href="css/sponsor5.css">
<!-- HTML5 shiv and Respond.js support IE8 or Older for HTML5 elements and media queries -->
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/html5shiv/3.7.3/html5shiv.min.js"></script>
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
<![endif]-->
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "BlogPosting",
"mainEntityOfPage": {
"@type": "WebPage",
"@id": "https://swiftrocks.com/understanding-dispatchqueues"
},
"image": [
"https://swiftrocks.com/images/thumbs/thumb_dark.jpg"
],
"datePublished": "2018-10-26T13:42:07+00:00",
"dateModified": "2020-04-12T14:00:00+02:00",
"author": {
"@type": "Person",
"name": "Bruno Rocha"
},
"publisher": {
"@type": "Organization",
"name": "SwiftRocks",
"logo": {
"@type": "ImageObject",
"url": "https://swiftrocks.com/images/thumbs/thumb_dark.jpg"
}
},
"headline": "Understanding DispatchQueues",
"abstract": "Multithreading in general is a difficult thing to fully understand, but understanding how the CPU deals with concurrency is the key to writing good, fast code that does what you expected it to do. Otherwise, you might be abusing your user's CPUs but thinking everything is fine because they are too fast for you to notice that something is wrong."
}
</script>
</head>
<body>
<div id="main">
<!-- Blog Header -->
<!-- Blog Post (Right Sidebar) Start -->
<div class="container">
<div class="col-xs-12">
<div class="page-body">
<div class="row">
<div><a class="logo-link" href="https://swiftrocks.com">
<img id="logo" class="logo" alt="SwiftRocks" src="images/bg/logo2dark.png">
</a>
<div class="menu-large">
<div class="menu-arrow-right"></div>
<div class="menu-header menu-header-large">
<div class="menu-item">
<a href="blog">blog</a>
</div>
<div class="menu-item">
<a href="about">about</a>
</div>
<div class="menu-item">
<a href="talks">talks</a>
</div>
<div class="menu-item">
<a href="projects">projects</a>
</div>
<div class="menu-item">
<a href="software-engineering-book-recommendations">book recs</a>
</div>
<div class="menu-item">
<a href="games">game recs</a>
</div>
<div class="menu-arrow-right-2"></div>
</div>
</div>
<div class="menu-small">
<div class="menu-arrow-right"></div>
<div class="menu-header menu-header-small-1">
<div class="menu-item">
<a href="blog">blog</a>
</div>
<div class="menu-item">
<a href="about">about</a>
</div>
<div class="menu-item">
<a href="talks">talks</a>
</div>
<div class="menu-item">
<a href="projects">projects</a>
</div>
<div class="menu-arrow-right-2"></div>
</div>
<div class="menu-arrow-right"></div>
<div class="menu-header menu-header-small-2">
<div class="menu-item">
<a href="software-engineering-book-recommendations">book recs</a>
</div>
<div class="menu-item">
<a href="games">game recs</a>
</div>
<div class="menu-arrow-right-2"></div>
</div>
</div>
</div>
<div class="content-page" id="WRITEIT_DYNAMIC_CONTENT">
<!--WRITEIT_POST_NAME=Understanding DispatchQueues-->
<!--WRITEIT_POST_HTML_NAME=understanding-dispatchqueues-->
<!--WRITEIT_POST_SITEMAP_DATE_LAST_MOD=2020-04-12T14:00:00+02:00-->
<!--WRITEIT_POST_SITEMAP_DATE=2018-10-26T13:42:07+00:00-->
<!--Add here the additional properties that you want each page to possess.-->
<!--These properties can be used to change content in the template page or in the page itself as shown here.-->
<!--Properties must start with 'WRITE_IT_POST'.-->
<!--Writeit provides and injects WRITEIT_POST_NAME and WRITEIT_POST_HTML_NAME by default.-->
<!--WRITEIT_POST_SHORT_DESCRIPTION=Multithreading in general is a difficult thing to fully understand, but understanding how the CPU deals with concurrency is the key to writing good, fast code that does what you expected it to do. Otherwise, you might be abusing your user's CPUs but thinking everything is fine because they are too fast for you to notice that something is wrong.-->
<title>Understanding DispatchQueues</title>
<div class="blog-post">
<div class="post-title-index">
<h1>Understanding DispatchQueues</h1>
</div>
<div class="post-info">
<div class="post-info-text">
Published on 14 Feb 2018
</div>
</div>
<i>What on earth are these "DispatchQueues"?<br></i>
<i>Why do I have to use it to send UI code to the main thread? It clearly still works if I do nothing.<br></i>
<i>What's the point of these "Quality of Services" queues? I use .main for everything and never had a problem.<br></i>
<i>Why do I get a crash if I call DispatchQueue.main.sync? What's the point of it?<br></i>
<i>Just what is this Main Thread anyway?</i>
<br>
<br>
<p>If you're developing iOS apps for more than a few weeks, then you have probably dealt with concurrent code before. If you have no background on Operating Systems, you may have asked yourself one of these questions.</p>
<div class="sponsor-article-ad-auto hidden"></div>
<p>Multithreading in general is a difficult thing to fully understand, but understanding how the CPU deals with concurrency is the key to writing good, fast code that does what you expected it to do. Otherwise, you might be abusing your user's CPUs but thinking everything is fine because they are too fast for you to notice that something is wrong.</p>
<p>But before we can answer these questions, we need to take a step back and understand how things work behind the scenes.</p>
<h2>What's a Process?</h2>
<p>The definition of a process is quite simple: it is a running program. Your app is a process, Slack is a process, Safari is a process, and so on. It contains a list of instructions (your code in <i>assembly</i> format) and sits there on your disk until the user wishes to run it. The OS will then load that process into memory, start an <b>instruction pointer</b> that tells us which instruction of the program is currently being executed, and have the CPU sequentially execute its instructions until they end, terminating the process.</p>
<pre><code>Address space of a single thread process
|- - - - - - - - - - - - - - - - - - - - - - - - - - |
| Instructions |
|- - - - - - - - - - - - - - - - - - - - - - - - - - -
| Global Data |
|- - - - - - - - - - - - - - - - - - - - - - - - - - -
| malloc'd data (Reference Types) |
|- - - - - - - - - - - - - - - - - - - - - - - - - - -
| Nothing (Stack and malloc'd data grow towards here)|
|- - - - - - - - - - - - - - - - - - - - - - - - - - -
| Stack (Value Types (if possible), args, returns) |
|- - - - - - - - - - - - - - - - - - - - - - - - - - -</code></pre>
<p>Each process gets its own section of physical memory dedicated to itself. They do not share these addresses with other processes.</p>
<h2>I'm reading something on Safari while listening to Spotify. How can the CPU run several processes at the same time?</h2>
<p>It can't. What you are experiencing is an illusion caused by the absurd speed of a modern CPU!.</p>
<p>A CPU simply cannot do two things at the same time. Things are slightly different for CPUs with multiple cores, but for simplicity, let's assume we only have one core; what happens is that it executes something in Safari, then something in Spotify, then something in iOS, then something in Safari again, and so on. The OS will save whatever the CPU was doing for a specific process in memory (in the form of registers and pointers), decide what will be the next process to run, retrieve what it was doing for that process, have the CPU run it for a while, and repeat. This is called a <b>context switch</b> and it happens very, very quickly, giving the impression it can actually run several things at once. (In CPUs with multiple cores the work can be divided between the cores, actually doing several things at once. However, the same principles apply when all the cores are in use.)</p>
<p>The exact way the OS decides what should be the next process to run is rather complex (read the book at the end of the article if you're interested), but what you should know is that it's possible to dictate manually what's the "priority" of something in our app. (Are iOS's "Quality of Services" starting to making sense now?)</p>
<h2>What's a Thread?</h2>
<p>Instead of the classic concept of a single thread process that starts at a <code>main()</code> function and ends at some <code>exit()</code> a few lines below, a multi-threaded program has more than one point of execution (each of which is being fetched and executed from). Perhaps another way to think of this is that each thread is very much like a separate process, except for one difference: they share the same address space and thus can access the same data.</p>
<pre><code>Address space of a multi-threaded process
|- - - - - - - - - - - - - - - - - - - - - - - - - - |
| Instructions |
|- - - - - - - - - - - - - - - - - - - - - - - - - - -
| Global Data |
|- - - - - - - - - - - - - - - - - - - - - - - - - - -
| malloc'd data (Reference Types) |
|- - - - - - - - - - - - - - - - - - - - - - - - - - -
| Nothing (Stack and malloc'd data grow towards here)|
|- - - - - - - - - - - - - - - - - - - - - - - - - - -
| Stack of Thread 2 |
|- - - - - - - - - - - - - - - - - - - - - - - - - - -
| Stack of Thread 1 |
|- - - - - - - - - - - - - - - - - - - - - - - - - - -</code></pre>
<p>Just like processes, a CPU cannot run two threads at the same time - they are instead targeted by <b>context switches</b> just like processes. The CPU runs something in Safari's Thread 1 (which is doing some UI updates), then something in Spotify's Thread 3 (which is downloading a song), then something in Safari's Thread 2 (which is pinging a DNS), and so on.</p>
<h2>iOS: The Main Thread</h2>
<p>Your iOS app has several threads. The <b>Main Thread</b> is simply the intial starting point of execution in your app (starting for you at <code>didFinishLaunchingWithOptions</code>). The Main Thread executes a loop every frame (a <code>RunLoop</code>) that draws the current screen if needed, handles UI events such as touches and executes the contents of the <code>DispatchQueue.main</code>. It keeps doing this until the app is terminated. It has extremely high priority - pretty much anything on it gets executed immediately. That's part of the reason why UI code is expected to be executed in the Main Thread - by executing some UI-changing code outside of it, your code might start running properly only to suddenly get <b>context switched</b> for several miliseconds because something more important arrived to the OS (like a notification). Your UI updates will then be delayed, giving a bad experience to your users. (In practice the topic of threading requirements for UI code is a bit more complicated than this, but for this purposes of this article we can assume it to be just as described.)</p>
<p>However, you can't simply execute <b>everything</b> on the Main Thread. Since this thread deals with everything related to screen draws / UI updates, if you run a huge task on it, it won't be able to do anything else until it ends. That's why we need several threads (points of execution) to begin with.</p>
<pre><code>@IBAction func actionOne(_ sender: Any) {
//Button actions are in the Main Thread.
//This takes about 5 seconds to finish
var counter = 0
for _ in 0..<1000000000 {
counter += 1
//The screen is totally frozen here. How can I scroll my screen (an UI action)
//If I blocked the thread by doing this meaningless thing?
//The scroll action is waiting to be run, but it can't because it's also a Main Thread action.
//You can't simply context switch actions on the same thread.
//This needs to be run in a different thread.
}
}</code></pre>
<h2>iOS: Background Threads and DispatchQueues</h2>
<p>A background thread is anything that is not the Main Thread. They can run alongside the Main Thread (like they were a different process, but remember the definition of a thread!), dealing with complex tasks without interferring with the Main Thread's UI updates. In iOS, the safest way of spawning a background thread is to use <code>DispatchQueues</code>. However, be aware that <b>DispatchQueues are not threads</b> - they are objects that <b>manage</b> a pool of threads. The queue will automatically create and reuse threads as it finds necessary in order to perform the work that you submit to it, abstracting from you the hassle of spawning threads manually and dealing with the potential issues of doing so.</p>
<p>Work dispatched to <code>DispatchQueue.main</code> will always be <b>serially</b> executed (that is, action 2 only happens after action 1 ends) on the Main Thread, while work dispatched to <code>DispatchQueue.global(qos:)</code> will <b>concurrently</b> (everything at the same time) perform work into one or more threads running in parallel (depending on the amount of work submitted to the queue) with priority equal to the priority of the selected QoS. If you'd like custom behavior (such as a queue that performs work on a background thread, but serially), you can create your own <code>DispatchQueue</code>.</p>
<p>You should be aware however that <b>global queues may also perform work in the Main Thread!</b> A very common misconception in iOS is to think that work dispatched to global queues will <b>always</b> run in a background thread, which is simply not true! Global queues can and will use the Main Thread every once in a while, so you should never write code that assumes that <i>Main Thread == Main Queue</i>. The following snippet is an example of this mistake that is present in many projects, and should be removed ASAP:</p>
<pre><code>// Never write this:
if Thread.isMainThread {
// We are 100% running on DispatchQueue.main!
}</code></pre>
<h2>Background Queue Priorities (QoS)</h2>
<p>By assigning a Quality of Service to an action, you indicate its importance, and the system prioritizes it and schedules it accordingly.</p>
<p>Because higher priority work is performed more quickly and with more resources than lower priority work, it typically requires more energy than lower priority work. Accurately specifying appropriate QoS classes for the work your app performs ensures that your app is responsive as well as energy efficient.</p>
<p>There are a few levels of QoS for background threads for several different kinds of actions, but none with higher priority than the Main Thread. These are the currently available Quality of Services:</p>
<ul>
<li>UserInteractive</li>
<li>UserInitiated</li>
<li>Utility</li>
<li>Background</li>
</ul>
<h2>Visualizing the impact of different QoS levels</h2>
<p>By using <b>Instruments</b>, we can see how the different QoS levels affect the execution of our code.</p>
<h2>Heavy task on the Main Thread</h2>
<pre><code>@IBAction func actionOne(_ sender: Any) {
//We already are in the main thread, but we will use a dispatch operation
//to see how long it takes for the task to begin.
DispatchQueue.main.async { [unowned self] in
self.timeIntensiveTask()
}
}</code></pre>
<div class="post-image margin-top-40 margin-bottom-40">
<img src="https://i.imgur.com/5h5izfu.png" alt="">
</div>
<p>The task got executed instantly after I pressed the IBAction, and took about 5 seconds to complete. However, the entire screen was frozen, as we blocked the thread.</p>
<h2>Heavy task on an UserInitiated QoS thread</h2>
<pre class="language-swift"><code>@IBAction func actionOne(_ sender: Any) {
DispatchQueue.global(qos: .userInitiated).async { [unowned self] in
self.timeIntensiveTask()
}
}</code></pre>
<div class="post-image margin-top-40 margin-bottom-40">
<img src="https://i.imgur.com/13G62Yw.png" alt="">
</div>
<p>A new thread spawned, and the task got executed almost instantly after I pressed the IBAction, also taking about 5 seconds to complete. No screen freeze this time! This thread is completely independent.</p>
<h2>Heavy task on a Background QoS thread</h2>
<pre class="language-swift"><code>@IBAction func actionOne(_ sender: Any) {
DispatchQueue.global(qos: .background).async { [unowned self] in
self.timeIntensiveTask()
}
}</code></pre>
<div class="post-image margin-top-40 margin-bottom-40">
<img src="https://i.imgur.com/jPgtDEt.png" alt="">
</div>
<p>Just like UserInitiated, a thread got spawned, but in this case, not only it took some time for the task to start - and it took almost 10 seconds for it to end! This lower priority thread had delayed and reduced access to system resources. However, this is good: If you're sending a task to a background QoS queue, it means you don't want to ruin your user's CPU by focusing on it. </p>
<h2>Visualizing Serial Queues versus Concurrent Queues</h2>
<pre class="language-swift"><code>@IBAction func actionOne(_ sender: Any) {
DispatchQueue.main.async { [unowned self] in
self.timeIntensiveTask()
}
DispatchQueue.main.async { [unowned self] in
self.timeIntensiveTask()
}
DispatchQueue.main.async { [unowned self] in
self.timeIntensiveTask()
}
}</code></pre>
<div class="post-image margin-top-40 margin-bottom-40">
<img src="https://i.imgur.com/MeS2Hbv.png" alt="">
</div>
<pre class="language-swift"><code>@IBAction func actionOne(_ sender: Any) {
DispatchQueue.global(qos: .background).async { [unowned self] in
self.timeIntensiveTask()
}
DispatchQueue.global(qos: .background).async { [unowned self] in
self.timeIntensiveTask()
}
DispatchQueue.global(qos: .background).async { [unowned self] in
self.timeIntensiveTask()
}
}</code></pre>
<div class="post-image margin-top-40 margin-bottom-40">
<img src="https://i.imgur.com/9menZsz.png" alt="">
</div>
<h2>DispatchQueue.sync vs DispatchQueue.async</h2>
<p>If the concept of a multi-threaded process wasn't mind-boggling enough, we need to careful with the definition of <code>.async</code> and <code>.sync</code> operations.</p>
<p>A common misconception is to think that <code>DispatchQueue.async</code> means executing something in background, and that's not true.</p>
<p>What will be the output on <code>actionOne()</code>?</p>
<pre class="language-swift"><code>@IBAction func actionOne(_ sender: Any) {
DispatchQueue.main.async { [unowned self] in
print("async started")
self.timeIntensiveTask()
print("async ended")
}
print("sync task started")
timeIntensiveTask()
print("sync task ended")
}
private func timeIntensiveTask() {
var counter = 0
for _ in 0..<1000000000 {
counter += 1
}
}</code></pre>
<p>The answer will always be:</p>
<pre class="language-swift"><code>sync task started
sync task ended
async task started
async task ended</code></pre>
<p>If you thought the two tasks would start together, just think about the context of this method: we are dispatching a task to the Main Thread, but <code>actionOne</code> is already on the Main Thread! There's no way a thread can run two sequences of instructions at the same time, that's why we have different threads.</p>
<p>The <code>async</code> task will also only execute after the <code>sync</code> task (and never before) because <code>DispatchQueue.main</code> tasks will only start executing at the end of the Main Thread's <code>RunLoop</code> - which is blocked by our sync task. If <code>actionOne</code> happened to be in a different thread or the <code>async</code> task happened to be in a different <code>DispatchQueue</code>, the tasks would start together in an order dependant to how fast the <code>async</code> task would be dispatched.</p>
<p>What <code>DispatchQueue.async</code> means is: <b>Make sure this task is eventually executed on thread X (main, or any other global background thread depending on what queue you are using), but I don't care about the details. I'll keep doing my stuff.</b> </p>
<p>On the contrary, <code>DispatchQueue.sync</code> means is: <b>Make sure this task is eventually executed on thread X. Please warn me when you do so, because I will also block myself (the calling thread) until this task finishes running.</b> </p>
<p>Given that, what do you think will be the output of the following <code>actionOne()</code>?</p>
<pre class="language-swift"><code>@IBAction func actionOne(_ sender: Any) {
DispatchQueue.main.sync { [unowned self] in
print("a")
}
print("b")
}</code></pre>
<p>A <code>sync</code> task is forwarded to the queue, and the main thread will freeze until <code>"a"</code> gets printed. The task gets sent to the Main Thread, which is frozen because it's waiting for the task to run. But the task can't run, because the thread is frozen waiting for the task to run, and on and on and on until your app decides to crash. You can't call <code>sync</code> dispatches from the thread itself, it has to come from somewhere else. Nothing will get printed here. As you most likely know, this is called a <b>deadlock</b>.</p>
<h2>What else?</h2>
<div class="sponsor-article-ad-auto hidden"></div>
<p>Concurrency is a very complex topic, and <code>DispatchQueues</code> are just one way to approach it in iOS. If you want to more about it, check out <a href="https://swiftrocks.com/thread-safety-in-swift">SwiftRocks's article about Thread Safety!</a></p>
<h2>References and Good reads</h2>
<a href="http://www.cs.albany.edu/~sdc/CSI500/Fal13/OSTEP/">Operating Systems: Three Easy Pieces</a>
<br>
<a href="https://developer.apple.com/library/content/documentation/Performance/Conceptual/EnergyGuide-iOS/PrioritizeWorkWithQoS.html">Apple Docs: QoS</a>
<br>
<a href="https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/Multithreading/CreatingThreads/CreatingThreads.html#//apple_ref/doc/uid/10000057i-CH15-SW2">Apple Docs: Thread Management</a>
<br>
<a href="https://medium.com/flawless-app-stories/basics-of-parallel-programming-with-swift-93fee8425287">Basic of Parallel Programming with Swift</a>
</div></div>
<div class="blog-post footer-main">
<div class="footer-logos">
<a href="https://swiftrocks.com/rss.xml"><i class="fa fa-rss"></i></a>
<a href="https://hachyderm.io/@rockbruno"><svg class="svg-logo-link" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--!Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2025 Fonticons, Inc.--><path d="M433 179.1c0-97.2-63.7-125.7-63.7-125.7-62.5-28.7-228.6-28.4-290.5 0 0 0-63.7 28.5-63.7 125.7 0 115.7-6.6 259.4 105.6 289.1 40.5 10.7 75.3 13 103.3 11.4 50.8-2.8 79.3-18.1 79.3-18.1l-1.7-36.9s-36.3 11.4-77.1 10.1c-40.4-1.4-83-4.4-89.6-54a102.5 102.5 0 0 1 -.9-13.9c85.6 20.9 158.7 9.1 178.8 6.7 56.1-6.7 105-41.3 111.2-72.9 9.8-49.8 9-121.5 9-121.5zm-75.1 125.2h-46.6v-114.2c0-49.7-64-51.6-64 6.9v62.5h-46.3V197c0-58.5-64-56.6-64-6.9v114.2H90.2c0-122.1-5.2-147.9 18.4-175 25.9-28.9 79.8-30.8 103.8 6.1l11.6 19.5 11.6-19.5c24.1-37.1 78.1-34.8 103.8-6.1 23.7 27.3 18.4 53 18.4 175z"/></svg></a>
<a href="https://twitter.com/rockbruno_"><i class="fa fa-twitter"></i></a>
<a href="https://github.com/rockbruno"><i class="fa fa-github"></i></a>
</div>
<div class="footer-text">
© 2026 Bruno Rocha
</div>
<div class="footer-text">
<p><a href="https://swiftrocks.com">Home</a> / <a href="blog">See all posts</a></p>
</div>
<div class="footer-text">
No AI has ever been used in this blog. Everything down to the HTML/CSS has been handcrafted by me.
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Blog Post (Right Sidebar) End -->
</div>
</div>
</div>
<!-- All Javascript Plugins -->
<script type="text/javascript" src="js/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM" crossorigin="anonymous"></script>
<script type="text/javascript" src="js/prism5.js"></script>
<!-- Main Javascript File -->
<script type="text/javascript" src="js/scripts30.js"></script>
<!-- Google tag (gtag.js) -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-H8KZTWSQ1R"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'G-H8KZTWSQ1R');
</script>
</body>
</html>