【发布时间】:2018-03-06 03:57:23
【问题描述】:
我想知道 Swift 4 变量是否是原子的。所以我做了以下测试。
以下是我的测试代码。
class Test {
var count = 0
let lock = NSLock()
func testA() {
count = 0
let queueA = DispatchQueue(label: "Q1")
let queueB = DispatchQueue(label: "Q2")
let queueC = DispatchQueue(label: "Q3")
queueA.async {
for _ in 1...1000 {
self.increase()
}
}
queueB.async {
for _ in 1...1000 {
self.increase()
}
}
queueC.async {
for _ in 1...1000 {
self.increase()
}
}
}
///The increase() method:
func increase() {
// lock.lock()
self.count += 1
print(count)
// lock.unlock()
}
}
输出如下,lock.lock() 和 lock.unlock() 评论。
3
3
3
4
5
...
2999
3000
输出如下,lock.lock() 和 lock.unlock uncommented。
1
2
3
4
5
...
2999
3000
我的问题
如果count变量是非原子变量,queueA、queueB和queueC应该异步调用increase(),导致随机访问和打印count。
所以,在我看来,有一个时刻,例如,queueA 和 queueB 得到 count 等于 15,它们都将 count 增加 1(count += 1),所以计数应该是16 即使执行了两次增加。
但是上面的三个队列只是从第一个开始随机开始计数,然后一切都按预期进行。
最后,我的问题是为什么count 打印有序?
更新:
问题解决了,如果你想像我做的那样做实验,做如下修改。
1.把increase()改成下面这样,你会得到合理的输出。
func increase() {
lock.lock()
self.count += 1
array.append(self.count)
lock.unlock()
}
2.输出方式:
@IBAction func tapped(_ sender: Any) {
let testObjc = Test()
testObj.testA()
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now()+3) {
print(self.testObj.array)
}
}
【问题讨论】:
-
不,Swift 的属性不是原子的,尽管 CPU 本身会对内存进行一些同步。请参阅 gist.github.com/robertmryan/b344f1605287254d01ce7937757c39a8 了解您的测试的排列,其中缺少同步可能会出现错误。
-
顺便说一句,检查线程清理选项(在方案设置中的诊断下),它将帮助您识别这些非线程安全的交互。
-
这也可能对您有所帮助:Are Swift variables atomic?
标签: swift