Skip to content

Instantly share code, notes, and snippets.

@gmertk
Forked from austinzheng/gcdexample.swift
Created March 9, 2016 09:49
Show Gist options
  • Save gmertk/558a99e769e9c1e5768e to your computer and use it in GitHub Desktop.
Save gmertk/558a99e769e9c1e5768e to your computer and use it in GitHub Desktop.
import Foundation
func main() {
print("Starting")
// GCD works by dispatching chunks of code (represented by closures, and called 'blocks') onto things called 'dispatch
// queues'. These queues run the blocks, either on the main thread or in a background thread. (Queues don't correspond
// to threads on a one-to-one basis; GCD is responsible for spinning up threads to service queues.)
// Here's a variable representing shared state I want to manipulate from different threads.
var value = 0
// I'm going to run 5 concurrent operations, for the sake of this demo.
let numberOfQueues = 5
// This is a closure representing some work I want to run in the background. I'll end up running it 5 times, to
// simulate 5 tasks. This closure is the 'block' I'll be submitting to my dispatch queue.
let doSomething = {
// The next two lines are work running on a background queue.
// Randomly sleep for some time between 0 and 5 seconds (usleep takes microseconds)
let someValue = arc4random_uniform(5000000)
usleep(someValue)
// Now, I'm going to dispatch back onto the main queue. The main queue is a special queue that represents tasks
// running on the main thread. It's often used for synchronization, in a similar way to how mutexes and locks might
// protect shared mutable state in a C program.
// THIS IS VERY IMPORTANT: if you have shared mutable state, YOU SHOULD ONLY MODIFY IT USING CODE RUNNING ON THE
// SAME SERIAL QUEUE (usually the main queue). This is a very common iOS application development pattern.
dispatch_async(dispatch_get_main_queue()) {
// Everything in this closure is happening on the main queue.
// Increment value by one.
value += 1
print("After waiting \(someValue) microseconds, 'value' is now \(value)")
if value == numberOfQueues {
// Once all 5 queues have returned, then kill the program.
print("All queues done, goodbye")
exit(EXIT_SUCCESS)
}
}
}
// WORKING WITH QUEUES:
// You can create dispatch queues yourself. The first argument is a C string that names the queue (and is optional, so
// I omitted it). The second argument determines whether the queue executes the blocks one at a time, or multiple
// blocks at once (concurrent). More info on that below.
// let runQueue = dispatch_queue_create(nil, DISPATCH_QUEUE_SERIAL)
// In addition to making queues, GCD comes with a couple of prebuilt queues. These 'global queues' are going to run on
// background threads. There are a couple of QOS_CLASS_* identifiers, which you can use to determine how important
// the code running on that queue is (and therefore what priority it'll get). The second argument is always 0.
// The global queues are *concurrent*, which means they don't need to wait for a block to finish before starting
// another one. Exactly how many blocks can run at once on a concurrent queue is determined by GCD. In practice this
// number is probably above 5, which means that all 5 of our tasks will start at the same time. However, if we had
// (e.g.) 100 tasks, some of those tasks might have to wait until earlier tasks are finished before they have a
// chance to start running.
let backgroundQueue = dispatch_get_global_queue(QOS_CLASS_DEFAULT, 0)
// DISPATCHING WORK ONTO QUEUES:
// Now, run my block (doSomething), five times.
dispatch_async(backgroundQueue, doSomething)
dispatch_async(backgroundQueue, doSomething)
dispatch_async(backgroundQueue, doSomething)
dispatch_async(backgroundQueue, doSomething)
dispatch_async(backgroundQueue, doSomething)
// dispatch_main() 'parks' the main thread and will run any blocks that are dispatched onto it. It doesn't return;
// once you call it your program belongs to GCD forever.
dispatch_main()
}
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment