Threadsafe Swift Collections
You may or may not face this issue while coding in swift. Collections like Array, Dictionary, Set are not threadsafe. One can experience an app crash if try to access the collection from one or more threads.
Collections in any language is an awesome feature. We can read/write in a collection to save/retrieve our data. Swift give us the privilege to work in a multithreading environment, in short, it means we can access the same variable from different threads.
But what happens if two thread tries to write over the same collection at one time or one thread is reading value while other thread is writing value. Do we get the most recent value from the collection? or app crash?
The answer to these questions is you can’t write to the same memory at a time. you should avoid reading while writing from the same memory.
What will be our implementation for thread-safe collections in Swift.
In Obj-c we have atomic and non-atomic to make our variable thread-safe and non-thread-safe. If we define a property with an atomic keyword, boom we have a thread-safe property, otherwise if is non-threadsafe.
Why we need non-thread-safe variable? Because thread-safe collection/variable/property make execution slower.
Thread-Safe collection
To have a thread-safe collection we need to define getter and setter. Whenever we are setting any collection we should make sure no other threads are currently executing over a collection. While reading a value from a collection we need to make sure, a value is provided to the reading thread.
Below code snippet shows how to create a safe dictionary. To get/set value from thread unsafe dictionary we need to have a concurrent queue. Sync block will deliver a value from the dictionary if it is presented while an async barrier is used to set a value to the dictionary.
A block submitted with flag .barrier will act as a barrier, all the blocks that were submitted before the barrier, will finish and only then the barrier block will execute. All blocks submitted after the barrier will not start until the barrier has finished.
Now question arise, why we use sync block in getter and async block in setter? Let’s understand this with an example:
In this picture, we have a train standing on the platform. Three passenger gets out of train, walk to the shop to buy some snacks. All passenger requested the shopkeeper to help them with snacks as all three passengers are in a hurry as the train is about to leave the platform. Now shopkeeper will take money from passenger 1 and give him snacks then take money from passenger 2 provide him snacks and so on. But what happens if the shopkeeper first taken money from all three passengers and then provide them with the snacks one by one. In the later process, if the train starts leaving station, then there is a possibility some of the passengers might not get snacks after paying money.
Now suppose passengers are thread requested for dictionary value from SafeDict class. If getters are async the dispatchQueue will not wait for the block to get executed and threads that requested dictionary value will continue their execution as dispatchQueue isn’t waiting for the getter block to get executed.
Second question can we use sync block in setter of dictionary?
Let’s understand this with the same example, if in between serving passenger shopkeeper receive lorry to fill items in its shop. Then what will shopkeeper do? Shopkeeper will ask lorry driver to put items at any corner of the shop, so that shopkeeper can place them at their respective place later on.
If we use sync block in setter then dispatchQueue will wait for setter block to finish, and getter blocks will also wait for the setter to get executed. We don’t want our getter block to wait as this can lead to a lag in execution. But async setter can lead, getter to fetch outdated values. Yes, it can if setter is not used with flag .barrier.
Thanks for reading this. Let me know your feedback.
Happy coding!