Swift4变量是原子的吗?

Swift4变量是原子的吗?,第1张

概述我想知道 Swift 4变量是否是原子的.所以我做了以下测试. 以下是我的测试代码. class Test { var count = 0 let lock = NSLock() func testA() { count = 0 let queueA = DispatchQueue(label: "Q1") 我想知道 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().

33345...29993000

输出如下,lock.lock()和lock.unlock取消注释.

12345...29993000

我的问题
如果count变量是非原子的,则queueA,queueB和queueC应异步调用increase(),这会导致随机访问和打印计数.

所以,在我看来,有一个时刻,例如,queueA和queueB得到的计数等于15,并且它们都将计数增加1(count = 1),所以即使有两个增加,计数也应该是16执行.

但是上面的三个队列只是在第一个开始时随机开始计算,然后一切都按照预期进行.

总而言之,我的问题是为什么计数有序打印?

更新:
问题解决了,如果您想按照我的方式进行实验,请执行以下更改.
1.将增加()改为下面,你会得到合理的输出.

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)        }    }

没有NSLock的输出:


使用NSLock输出:
[1,2,3,…,2999,3000]

解决方法 不,默认情况下,Swift属性不是原子的,是的,很可能你会遇到多线程问题,多线程使用该属性的过时值,这个属性刚刚更新.

但在我们开始追逐之前,让我们看看原子财产是什么.

An atomic property is one that has an atomic setter – i.e. while the setter does it’s job other threads that want to access (get or set) the property are blocked.

现在在你的代码中我们不是在谈论一个原子属性,因为= operation实际上被分成了至少三个 *** 作:

>获取当前值,将其存储在cpu寄存器中
>增加cpu寄存器
>将递增的值存储到属性中

即使setter是原子的,我们也可能会遇到两个线程“同时”到达#1并尝试在相同值上运行的情况.

所以这里的问题应该是:是()一个原子 *** 作吗?

现在回到实际的代码,这是“救援”你的打印电话.增量和存储 *** 作需要很短的时间,而打印需要更长的时间.这就是为什么你似乎没有遇到竞争条件,因为多个线程可以使用过时值的窗口非常小.

请尝试以下 *** 作:取消注释打印调用,并在足够大的时间后打印计数值,以便所有后台线程完成(2秒应足以进行1000次迭代):

let t = test()t.testA()dispatchQueue.main.asyncAfter(deadline: .Now() + 2.0) {    // you're likely to get different results each run    print(t.count)}RunLoop.current.run()

您现在将看到锁定版本提供一致的结果,而非锁定版本则不会.

总结

以上是内存溢出为你收集整理的Swift4变量是原子的吗?全部内容,希望文章能够帮你解决Swift4变量是原子的吗?所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://www.outofmemory.cn/web/1008079.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-22
下一篇 2022-05-22

发表评论

登录后才能评论

评论列表(0条)

保存