【问题标题】:Safety of using an empty reference instance across multiple threads跨多个线程使用空引用实例的安全性
【发布时间】:2020-08-11 07:14:34
【问题描述】:

背景

我有一个类Data,它存储多个输入参数和一个输出值。

只要输入参数之一发生突变,就会重新计算输出值。

计算需要相当长的时间,因此它是异步执行的。

如果在重新计算过程中输入参数之一发生变化,则取消当前计算,并开始新的计算。

取消逻辑是通过计算操作的序列化队列和键(参考实例)(Data.key)实现的。每次将新的重新计算添加到队列时,Data.key 都会设置为新的引用实例。此外,由于队列,一次只能进行一次重新计算。任何正在执行的重新计算都会不断检查它是否是最近启动的计算,方法是保存对启动时使用它创建的密钥和当前存在的密钥的引用。如果它们不同,则新的重新计算从开始就已排队,它将终止。

这将触发队列中的下一次重新计算开始,重复该过程。

我的问题的依据

Data.key 的重新分配在主线程上完成。

当前计算不断检查它的键是否与当前的相同。这意味着另一个线程不断地访问Data.key

问题

Data.key 容易被同时读取/写入对我来说安全吗?

是否可以同时读取和写入一个属性?

【问题讨论】:

  • 就我在这种特殊情况下的理解而言,没有问题,因为您一遍又一遍地访问该属性,如果您的属性不是这个特定周期的最新版本,这并不重要。关于如何在 swift 4 及更高版本中管理冲突访问有一个很好的解释:github.com/apple/swift-evolution/blob/master/proposals/…github.com/apple/swift/blob/master/docs/OwnershipManifesto.md
  • @shoe 重新计算是一个循环? like this ``` repeat { // 一些繁重的同步代码,例如将 NSData 转换为 UIImage } while taskKey == currentKey ``
  • @Mark 差不多。除了使用=== 运算符。

标签: ios swift multithreading concurrency


【解决方案1】:

是的,Data.Key 容易被同时读取/写入。
这是我从主线程写入密钥并从 MySerialQueue 读取的示例。
如果您运行该代码,有时它会崩溃。
由于取消引用指向主队列写入期间释放的内存的指针而发生崩溃。 Xcode 有一个叫做 ThreadSanitizer 的功能,它可以帮助解决这些问题。
Discussion About Race condition

func experiment() {
    var key = MyClass()
    var key2 = MyClass()
    
    class MyClass {}
    
    func writer() {
        for _ in 0..<1000000 {
            key = MyClass()
        }
    }
    
    func reader() {
        for _ in 0..<1000000 {
            if key === key2 {}
        }
    }
    
    DispatchQueue.init(label: "MySerialQueue").async {
        print("reader begin")
        reader()
        print("reader end")
    }
    
    DispatchQueue.main.async {
        print("writer begin")
        writer()
        print("writer end")
    }
}

【讨论】:

    【解决方案2】:

    问: 让 Data.key 容易被同时读取/写入对我来说是否安全? A: 没有

    问: 甚至可以同时读取和写入属性吗? A: 是的,为 Data.Key 创建一个单独的队列,您只能通过它访问它。只要在此队列中限制任何操作(获取/设置),您就可以在线程安全的任何地方读取或写入。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-07-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-07-19
      • 2011-01-13
      相关资源
      最近更新 更多