【问题标题】:Variable Multithread Access - Corruption可变多线程访问 - 损坏
【发布时间】:2018-12-26 16:52:33
【问题描述】:

简而言之:

我有一个可从多个线程访问的计数器变量。虽然我已经实现了多线程读/写保护,但变量似乎仍然 - 以一种不一致的方式 - 同时被写入,导致计数器的结果不正确。

进入杂草:

我使用“for 循环”在后台触发大约 100 个 URL 请求,每个请求都在其“DispatchQueue.global(qos: .userInitiated).async”队列中。

这些进程是异步的,一旦完成,它们就会更新“计数器”变量。这个变量应该是多线程保护的,这意味着它总是从一个线程访问并且是同步访问的。然而,有些事情是错误的,有时两个线程会同时访问变量,导致计数器没有正确更新。这是一个示例,假设我们有 5 个 URL 需要获取:

我们从 5 处的 Counter 变量开始。

1 URL 请求完成 -> 计数器 = 4

2 URL 请求完成 -> 计数器 = 3

3 URL 请求完成 -> 计数器 = 2

4 URL 请求完成(出于某种原因——我假设变量被同时访问)-> 计数器 2

5 URL 请求完成 -> 计数器 = 1

如您所见,这导致计数器为 1,而不是 0,这会影响代码的其他部分。此错误发生不一致。

这是我对计数器变量使用的多线程保护:

  1. 专用全局队列

//后台队列同步数据访问文件private let globalBackgroundSyncronizeDataQueue = DispatchQueue(标签: "globalBackgroundSyncronizeSharedData")

  1. 始终通过访问器访问变量:
var numberOfFeedsToFetch_Value: Int = 0
var numberOfFeedsToFetch: Int {
    set (newValue) {
        globalBackgroundSyncronizeDataQueue.sync()  {
            self.numberOfFeedsToFetch_Value = newValue
        }
    }
    get {
        return globalBackgroundSyncronizeDataQueue.sync {
            numberOfFeedsToFetch_Value
        }
    }
}

我认为我可能遗漏了一些东西,但我使用了分析并且一切似乎都很好,还检查了文档,我似乎正在做他们推荐的事情。非常感谢您的帮助。

谢谢!!

【问题讨论】:

  • 如何使用锁定机制NSLock

标签: swift multithreading queue dispatch


【解决方案1】:

来自 Apple 论坛的回答:https://forums.developer.apple.com/message/322332#322332

单独的访问器是线程安全的,但是一个增量操作 鉴于您编写代码的方式,这不是原子的。也就是说,虽然一个 线程正在获取或设置值,没有其他线程也可以 获取或设置值。然而,没有什么可以阻止 线程 A 从读取当前值(例如 2),线程 B 读取 相同的当前值 (2),每个线程在它们的 私人临时,然后每个线程写他们的增量 属性的值(两个线程均为 3)。所以,两个线程 增加但属性没有从 2 变为 4;它只是从 2到3.你需要做整个增量操作(get,increment 以原子方式设置私有值,这样其他线程都不能 在进行时读取或写入属性。

【讨论】:

    猜你喜欢
    • 2012-08-02
    • 1970-01-01
    • 2023-03-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-07-01
    • 2020-09-26
    相关资源
    最近更新 更多