变量多线程访问 - 损坏

Variable Multithread Access - Corruption

简而言之:

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

进入杂草丛生:

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

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

我们从 Counter 变量 5 开始。

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

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

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

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

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

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

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

  1. 专用全局队列

//Background queue to syncronize data access fileprivate let globalBackgroundSyncronizeDataQueue = DispatchQueue(label: "globalBackgroundSyncronizeSharedData")

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

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

谢谢!!

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

The individual accessors are thread safe, but an increment operation isn't atomic given how you've written the code. That is, while one thread is getting or setting the value, no other threads can also be getting or setting the value. However, there's nothing preventing thread A from reading the current value (say, 2), thread B reading the same current value (2), each thread adding one to this value in their private temporary, and then each thread writing their incremented value (3 for both threads) to the property. So, two threads incremented but the property did not go from 2 to 4; it only went from 2 to 3. You need to do the whole increment operation (get, increment the private value, set) in an atomic way such that no other thread can read or write the property while it's in progress.