GCD 真的是线程安全的吗?
is GCD really Thread-Safe?
我学过GCD和Thread-Safe。
在苹果文档中,GCD 是线程安全的,即多线程可以访问。
而且我了解了线程安全的含义,即每当多个线程访问某个对象时总是给出相同的结果。
我认为Thread-Safe 和GCD 的Thread-Safe 的意思是不一样的,因为我测试了下面写的一些情况,求和0 到9999。
"something.n" 当我多次执行下面的代码时,值不一样。
如果 GCD 是线程安全的,为什么“something.n”值不同?
我真的很困惑..你能帮我吗?
我真的很想掌握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)
}
}
}
您当前的队列是并发的
var concurrentQueue = DispatchQueue(label: "asdf", attributes: . concurrent)
这意味着代码可以 运行 在每个 async
中以任何顺序排列
Every run has a different order but variable is accessed only by one part at a time
你说:
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.
他们说的是同一件事。只有在同时从不同线程调用它是安全的情况下,一个代码块才是线程安全的(并且这种线程安全是通过确保代码的关键部分不能在一个线程上 运行 来实现的)与另一个线程同时进行。
但让我们明确一点:Apple 并不是说如果您使用 GCD,您的代码就自动是线程安全的。是的,调度队列对象本身是线程安全的(即您可以安全地从您想要的任何线程调度到队列),但这并不意味着您自己的代码一定是线程安全的。如果一个人的代码同时从多个线程访问同一内存,则必须提供自己的同步以防止写入与任何其他访问同时进行。
在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 中提供了多种实现线程安全的方法。
但请注意,Apple 并未引入“线程安全”的不同定义。正如他们在上述 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.
并且在引入 GCD 时发布的 Concurrency Programming Guide: Migrating Away from Threads: Eliminating Lock-Based Code 中,Apple 说:
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.
但他们并不是说你可以只使用 GCD 并发队列并自动实现线程安全,而是说通过谨慎和正确使用 GCD 队列,可以在不使用锁的情况下实现线程安全。
顺便说一句,Apple 提供了工具来帮助您诊断您的代码是否是线程安全的,即 Thread Sanitizer (TSAN)。参见 Diagnosing Memory, Thread, and Crash Issues Early。
我学过GCD和Thread-Safe。 在苹果文档中,GCD 是线程安全的,即多线程可以访问。 而且我了解了线程安全的含义,即每当多个线程访问某个对象时总是给出相同的结果。
我认为Thread-Safe 和GCD 的Thread-Safe 的意思是不一样的,因为我测试了下面写的一些情况,求和0 到9999。
"something.n" 当我多次执行下面的代码时,值不一样。 如果 GCD 是线程安全的,为什么“something.n”值不同?
我真的很困惑..你能帮我吗? 我真的很想掌握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)
}
}
}
您当前的队列是并发的
var concurrentQueue = DispatchQueue(label: "asdf", attributes: . concurrent)
这意味着代码可以 运行 在每个 async
Every run has a different order but variable is accessed only by one part at a time
你说:
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.
他们说的是同一件事。只有在同时从不同线程调用它是安全的情况下,一个代码块才是线程安全的(并且这种线程安全是通过确保代码的关键部分不能在一个线程上 运行 来实现的)与另一个线程同时进行。
但让我们明确一点:Apple 并不是说如果您使用 GCD,您的代码就自动是线程安全的。是的,调度队列对象本身是线程安全的(即您可以安全地从您想要的任何线程调度到队列),但这并不意味着您自己的代码一定是线程安全的。如果一个人的代码同时从多个线程访问同一内存,则必须提供自己的同步以防止写入与任何其他访问同时进行。
在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
但请注意,Apple 并未引入“线程安全”的不同定义。正如他们在上述 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.
并且在引入 GCD 时发布的 Concurrency Programming Guide: Migrating Away from Threads: Eliminating Lock-Based Code 中,Apple 说:
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.
但他们并不是说你可以只使用 GCD 并发队列并自动实现线程安全,而是说通过谨慎和正确使用 GCD 队列,可以在不使用锁的情况下实现线程安全。
顺便说一句,Apple 提供了工具来帮助您诊断您的代码是否是线程安全的,即 Thread Sanitizer (TSAN)。参见 Diagnosing Memory, Thread, and Crash Issues Early。