2

I have studied GCD and Thread-Safe. In apple document, GCD is Thread-Safe that means multiple thread can access. And I learned meaning of Thread-Safe that always give same result whenever multiple thread access to some object.

I think that meaning of Thread-Safe and GCD's Thread-Safe is not same because I tested some case which is written below to sum 0 to 9999.

"something.n" value is not same when I excute code below several time. If GCD is Thread-Safe , Why isn't "something.n" value same ?

I'm really confused with that.. Could you help me? I really want to master Thread-Safe!!!

class Something {
    var n = 0
}
class ViewController: UIViewController {
    let something = Something()
    var concurrentQueue = DispatchQueue(label: "asdf", attributes: .concurrent)
    override func viewDidLoad() {
        super.viewDidLoad()
        let group = DispatchGroup()
        for idx in 0..<10000 {
            concurrentQueue.async(group: group) {
                self.something.n += idx
            }
        }
    
        group.notify(queue: .main ) {
            print(self.something.n)
        }
    }
}
HyunSu
  • 155
  • 7
  • “In apple document ...” - If you should share the link to the doc in question, and quote the relevant excerpt, we can probably better clarify what they were saying. – Rob Mar 07 '21 at 16:36
  • Completely unrelated, but be very wary of large `for` loops, dispatching asynchronously to some queue. This is the text book definition of “thread explosion” and because the number of GCD worker threads is quite limited, can lead to suboptimal performance and, in some scenarios, even deadlocks. I'm sure the above code snippet was just for illustrative purposes, but in general, avoid thread explosion. E.g. https://gist.github.com/robertmryan/fb65510f42e315f24859cd5a24efae4f – Rob Mar 07 '21 at 17:17
  • https://developer.apple.com/library/archive/documentation/General/Conceptual/ConcurrencyProgrammingGuide/OperationQueues/OperationQueues.html , at the bottom of the page, " Dispatch queues themselves are thread safe. In other words, you can submit tasks to a dispatch queue from any thread on the system without first taking a lock or synchronizing access to the queue." – HyunSu Mar 08 '21 at 03:30
  • Oh, You are so kind. I really appreciate you. Thank you!! Yes I just need to check purpose. Oh, Thank you for giving concurrentPerfom(). – HyunSu Mar 08 '21 at 03:36
  • 2
    Ah, I understand the confusion now. All they’re saying is that when you use dispatch queues, you can safely use them from any thread you want (which is 100% true). But that doesn’t mean that the code you write using GCD is inherently thread-safe! If you want to write thread-safe code, you have to make it thread-safe yourself. All they’re saying is that the queue, itself, is safe to use from whatever thread you want. – Rob Mar 08 '21 at 04:47
  • yes yes I really want to know what you said. So we can use GCD, but if you want to write thread-safe code, you must provide synchroinzation. Right?!! Thank you!! I really approciate you. It is really precious to me that you give answer. thank you!!!! – HyunSu Mar 08 '21 at 05:20

2 Answers2

5

You said:

I have studied GCD and Thread-Safe. In apple document, GCD is Thread-Safe that means multiple thread can access. And I learned meaning of Thread-Safe that always give same result whenever multiple thread access to some object.

They are saying the same thing. A block of code is thread-safe only if it is safe to invoke it from different threads at the same time (and this thread safety is achieved by making sure that the critical portion of code cannot run on one thread at the same time as another thread).

But let us be clear: Apple is not saying that if you use GCD, that your code is automatically thread-safe. Yes, the dispatch queue objects, themselves, are thread-safe (i.e. you can safely dispatch to a queue from whatever thread you want), but that doesn’t mean that your own code is necessarily thread-safe. If one’s code is accessing the same memory from multiple threads concurrently, one must provide one’s own synchronization to prevent writes simultaneous with any other access.

In the Threading Programming Guide: Synchronization, which predates GCD, Apple outlines various mechanisms for synchronizing code. You can also use a GCD serial queue for synchronization. If you using a concurrent queue, one achieves thread safety if you use a “barrier” for write operations. See the latter part of this answer for a variety of ways to achieve thread safety.

But be clear, Apple is not introducing a different definition of “thread-safe”. As they say in that aforementioned guide:

When it comes to thread safety, a good design is the best protection you have. Avoiding shared resources and minimizing the interactions between your threads makes it less likely for those threads to interfere with each other. A completely interference-free design is not always possible, however. In cases where your threads must interact, you need to use synchronization tools to ensure that when they interact, they do so safely.

And in the Concurrency Programming Guide: Migrating Away from Threads: Eliminating Lock-Based Code, which was published when GCD was introduced, Apple says:

For threaded code, locks are one of the traditional ways to synchronize access to resources that are shared between threads. ... Instead of using a lock to protect a shared resource, you can instead create a queue to serialize the tasks that access that resource.

But they are not saying that you can just use GCD concurrent queues and automatically achieve thread-safety, but rather that with careful and proper use of GCD queues, one can achieve thread-safety without using locks.


By the way, Apple provides tools to help you diagnose whether your code is thread-safe, namely the Thread Sanitizer (TSAN). See Diagnosing Memory, Thread, and Crash Issues Early.

Rob
  • 415,655
  • 72
  • 787
  • 1,044
  • Oh my god. I wondered that I will be happy if Rob add answer to me. I can't believe. Before I ask you something, I should tell you that I am really happy and appreciate you. Okay. I read your comment many times. “ Apple is not saying that you can use GCD to safely access from multiple threads.” is hitting me. I almost understand Thread-safe. – HyunSu Mar 08 '21 at 03:16
  • Serial Queue is to excute task in order waiting until task complete . So This is Thread safe in Serial Queue. But Concurrent queue is to excute task in order but, not waiting task complete. So this is not thread safe. Right? But Why did Apple introduce GCD with it is Thread-Safe ? I think that “GCD is Thread Safe, but if you use concurrent queue , that is not Thread-safe until you provide synchronization. “ Can I rechange like that ? Because some people like me should understand “ GCD is Thread-safe! , So, All of Queue of GCD is always Thread-safe! “ – HyunSu Mar 08 '21 at 03:16
  • 2
    Dispatch queues can be accessed from whatever thread you want because the queues, themselves, are thread-safe. That’s a completely different question than whether our code that is using GCD happens to be thread-safe or not. For this, we have to reason about our code and figure out whether we have any “data races” (where two different threads might be trying to access the same unsynchronized resource at the same time). And if we did have a data race, we could solve that in a variety of ways, GCD or otherwise. But don’t conflate the thread-safety of the queue with the thread-safety of our code. – Rob Mar 08 '21 at 04:46
  • 1
    Thank you!! You are angel for me. I just think that " I can get thread-safe code by using Dispatch queue , because Dispatch queue , themsevles, are thread-safe " but my assumption was wrong! thank you. – HyunSu Mar 08 '21 at 05:29
1

Your current queue is concurrent

var concurrentQueue = DispatchQueue(label: "asdf", attributes: . concurrent)

which means that code can run in any order inside every async

Every run has a different order but variable is accessed only by one part at a time

Shehata Gamal
  • 98,760
  • 8
  • 65
  • 87
  • yeah I know that is concurrent queue and excuted on any order. But Why isn't same total sum? Even if queue is concurrent queue, Shouldn't result of sum be same ? because Thread-Safe give same result. – HyunSu Mar 07 '21 at 10:48
  • 1
    As when you add `self.something.n` to itself it's value could be different at time of addition caused by execution of any other part , You mix thread safty with order , thread safety will guranate variable is accessed from 1 part at any time , while order could cause the sum to be different – Shehata Gamal Mar 07 '21 at 10:48
  • Oh. Yes! Thank you. I almost understand. Many people say that object which will be accessed by multiple process should be Thread-safe by using semaphore or lock etc. like that https://www.objc.io/blog/2018/12/18/atomic-variables/ So Can I unserstand that its Thread-safe is little bit different with meaning of GCD-Thread-safe ? – HyunSu Mar 07 '21 at 10:57
  • 1
    @HyunSu No, Apple does not have a different definition of thread-safety. – Rob Mar 07 '21 at 19:41