代码之家  ›  专栏  ›  技术社区  ›  Nishant Tyagi

在swift中避免数据竞争

  •  3
  • Nishant Tyagi  · 技术社区  · 6 年前

    当我运行TSan工具时,我在代码中得到了竞争条件。因为同一代码同时从不同的队列和线程访问,所以我不能使用串行队列或屏障,因为队列只会阻止单个队列访问共享资源,而不会阻止其他队列。

    我曾经 objc_sync_enter(object) | objc_sync_exit(object) 和锁 NSLock() or NSRecursiveLock()

    当我使用 @synchronized() 关键字来保护共享资源,它的工作正常,正如预期的那样,我没有得到特定代码块的竞争条件。

    那么,我们不能使用Swift保护数据的替代方案是什么呢 @已同步() Swift语言中的关键字。

    PFA截图供参考- Data Race

    1 回复  |  直到 6 年前
        1
  •  8
  •   Rob Napier    4 年前

    我不明白“我不能使用串行队列或屏障,因为队列只会阻止单个队列访问共享资源,而不会阻止其他队列。”使用队列是解决这个问题的标准方法。

    class MultiAccess {
        private var _property: String = ""
        private let queue = DispatchQueue(label: "MultiAccess")
        var property: String {
            get {
                var result: String!
                queue.sync {
                    result = self._property
                }
                return result
            }
            set {
                queue.async {
                    self._property = newValue
                }
            }
        }
    }
    

    通过这种结构,可以 property 是原子的和线程安全的,无需调用方做任何特殊的操作。请注意,这有意为类使用单个队列,而不是为每个属性使用队列。通常,您希望相对较少的队列做大量的工作,而不是大量的队列做少量的工作。如果您发现您正在从许多不同的线程访问一个可变对象,您需要重新考虑您的系统(可能减少线程的数量)。没有一种简单的模式可以让它高效、安全地工作,而不必仔细考虑特定的用例。

    但这种构造对于系统框架可能以最小争用率在随机线程上回调的问题非常有用。它很容易实现,也很容易正确使用。如果你有一个更复杂的问题,你必须为这个问题设计一个解决方案。


    编辑:我很久没想过这个答案了,但布伦南的评论让我重新注意到了这个问题。因为我在原始代码中有一个bug,我的原始答案是可以的,但是如果你修复了这个bug,它是不好的。(如果你想看到我的原始代码使用了一个屏障,请查看编辑历史记录,我不想把它放在这里,因为人们会复制它。)我已将其更改为使用标准串行队列而不是并发队列。