15

I often come across the key terms "thread safe" and wonder what it means. For example, in Firebase or Realm, some objects are considered "Thread Safe". What exactly does it mean for something to be thread safe?

atiqkhaled
  • 386
  • 4
  • 19
Ali Mir
  • 565
  • 7
  • 20
  • See the comments about thread safety on my answer here. Relevant. http://stackoverflow.com/questions/588866/whats-the-difference-between-the-atomic-and-nonatomic-attributes/589392#589392 – bbum Dec 30 '16 at 17:50
  • Some similar discussion here, including a Swift example at the end of my answer: http://stackoverflow.com/a/34386923/23649 – jtbandes Dec 30 '16 at 19:38

5 Answers5

13

Thread Unsafe - If any object is allowed to modify by more than one thread at the same time. Thread Safe - If any object is not allowed to modify by more than one thread at the same time.

Generally, immutable objects are thread-safe.

Saurabh
  • 745
  • 1
  • 9
  • 33
Divesh singh
  • 409
  • 4
  • 12
9

An object is said to be thread safe if more than one thread can call methods or access the object's member data without any issues; an "issue" broadly being defined as being a departure from the behaviour when only accessed from only one thread.

For example an object that contains the code i = i + 1 for a regular integer i would not be thread safe, since two threads might encounter that statement and one thread might read the original value of i, increment it, then write back that single incremented value; all at the same time as another thread. In that way, i would be incremented only once, where it ought to have been incremented twice.

Bathsheba
  • 231,907
  • 34
  • 361
  • 483
6

After searching for the answer, I got the following from this website:

Thread safe code can be safely called from multiple threads or concurrent tasks without causing any problems (data corruption, crashing, etc). Code that is not thread safe must only be run in one context at a time. An example of thread safe code is let a = ["thread-safe"]. This array is read-only and you can use it from multiple threads at the same time without issue. On the other hand, an array declared with var a = ["thread-unsafe"] is mutable and can be modified. That means it’s not thread-safe since several threads can access and modify the array at the same time with unpredictable results. Variables and data structures that are mutable and not inherently thread-safe should only be accessed from one thread at a time.

Ali Mir
  • 565
  • 7
  • 20
2

iOS Thread safe

[Atomicity, Visibility, Ordering]
[General lock, mutex, semaphore]

Thread safe means that your program works as expected. It is about multithreading envirompment, where we have a problem with shared resource with problems of Data races and Race Condition[About].

Apple provides us by Synchronization Tools:

Atomicity

  • Atomic Operations - lock free mechanism which is based on hardware instructions - for example Compare-And-Swap(CAS)[More]...

Visibility

  • Volatile Variable - read value from memory(no cache)
    • Objective-C volatile

Ordering

  • Memory Barriers - guarantees up-to date data[About]
    • Objective-C OSMemoryBarrier

Find problem in your code

Thread Sanitizer - uses self.recordAndCheckWrite(var) inside to figure out when(timestamp) and who(thread) access to variable

Synchronisation

  • Locks - thread can get a lock and nobody else access to the resource. NSLock.

    • Semaphore consists of Threads queue, Counter value and has wait() and signal() api. Semaphore allows a number of threads(Counter value) work with resource at a given moment. DispatchSemaphore, POSIX Semaphore - semaphore_t. App Group allows share POSIX semaphores
    • Mutex - mutual exclusion, mutually exclusive - is a type of Semaphore(allows several threads) where Thread can acquire it and is able to work with block as a single encroacher, all others thread will be blocked until release. The main different with lock is that mutex also works between processes(not only threads). Also it includes memory barrier.
      var lock = os_unfair_lock_s()
      os_unfair_lock_lock(&lock)
      //critical section
      os_unfair_lock_unlock(&lock)
    

    NSLock -POSIX Mutex Lock - pthread_mutex_t, Objective-C @synchronized.

    let lock = NSLock()
    lock.lock()
    //critical section
    lock.unlock()
    
    • Recursive lock - Lock Reentrance - thread can acquire a lock several times. NSRecursiveLock
    • Spin lock - waiting thread checks if it can get a lock repeatedly based on polling mechanism. It is useful for small operation. In this case thread is not blocked and expensive operations like context switch is not nedded
  • [GCD]

    Common approach is using custom serial queue with async call - where all access to memory will be done one by one:

    serial read and write access

    private let queue = DispatchQueue(label: "com.company")
    self.queue.async {
        //read and write access to shared resource
    }
    

    concurrent read and serial write access. when write is oocured - all previous read access finished -> write -> all other reads

    private let queue = DispatchQueue(label: "com.company", attributes: .concurrent)
    //read
    self.queue.sync {
        //read
    }
    
    //write
    self.queue.sync(flags: .barrier) {
        //write
    }
    
    
  • Operations

  • [Actors]

    actor MyData {
        var sharedVariable = "Hello"
    }
    
    //using
    Task {
        await self.myData.sharedVariable = "World"
    }
    

Multi threading:

yoAlex5
  • 29,217
  • 8
  • 193
  • 205
0

To give a simple example. If something is shared across multiple threads without any issues like crash, it is thread-safe. For example, if you have a constant (let value = ["Facebook"]) and it is shared across multiple threads, it is thread safe because it is read-only and cannot be modified. Whereas, if you have a variable (var value = ["Facebook"]), it may cause potential crash or data loss when shared with multiple threads because it's data can be modified.