Multi Thread access to shared Variables – Swift 4 Concurrency

Working with background threads really helps improve the app responsiveness & the overall user experience. But, and it’s a big but, you have to be aware of multithread access conflicts. 

Screen Shot 2018 06 17 at 11 01 43 AM

If you access/modify the same variable from multiple threads you’re prone to non-reproducible -seemingly random- crashes.

How to Detect Conflicts?

To help you find where you may have this variable access conflicts you should enable Thread Sanitizer & Pause on issues in your Run Scheme settings. Xcode will highlight conflicts while the app runs, as it detects them. If you want to dig deeper in what the debugger can do for you there’s a great WWDC 2018 session worth watching

Screen Shot 2018 06 17 at 10 29 38 AM

Once we have detected the variables that are being accessed from different threads it’s time to strengthen them.

How to Address Multi-Thread Variable Access Conflicts?

We must protect the access to the variables so that no simultaneous read/write action can occur. The easiest way is to use accessors for the variable, accessors can be accessed from any thread but the value of the variable always will be fetched from one thread (that we create for this purpose). Here’s an example to illustrate:

    //Background queue to synchronize data access

    fileprivate let globalBackgroundSyncronizeDataQueue = DispatchQueue(

        label: globalBackgroundSyncronizeSharedData”)

 

    //Value variable (always accessed from created thread) 

    var arrayOfFeedItems_Value : [String] =  []

 

    //Variable accessor that can be accessed from anywhere (multithread-protected).

    var arrayOfFeedItems : [String] {

        set(newValue){

            globalBackgroundSyncronizeDataQueue.sync(){

                self.arrayOfFeedItems_Value = newValue

            }

        }

        get{

            return globalBackgroundSyncronizeDataQueue.sync{

                arrayOfFeedItems_Value

            }

        }

 

    }

In this case I’m adding multi-thread protection to an array (arrayOfFeedItems), but you could do the same with any variable. 

This has been a fun learning experience for me, hope this post helps other with the same challenges.

Questions / comments? I’m at @MarcMasVi 

Marc

 

Some extra documentation if you want to dig deeper: Swift Access Races & Framework Dispatch.