可变多线程访问-损坏



简而言之:

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

进入杂草:

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

这些进程是异步的,一旦它们完成,就会更新一个"计数器"变量。这个变量应该是多线程保护的,这意味着它总是从一个线程访问,并且是同步访问的。然而,出现了问题,两个线程会不时同时访问变量,导致计数器无法正确更新。这里有一个例子,假设我们有5个URL要获取:

我们从计数器变量5开始。

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

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

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

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

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

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

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

  1. 专用全局队列

//同步数据访问fileprivatelet的后台队列globalBackgroundSyncronizeDataQueue=调度队列(标签:"globalBackgroundSyncronizeSharedData"(

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

我想我可能遗漏了一些东西,但我使用了评测,一切似乎都很好,还检查了文档,我似乎正在按照他们的建议行事。真的很感谢你的帮助。

谢谢!!

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

单个访问器是线程安全的,但是增量操作考虑到您编写代码的方式,它不是原子的。也就是说线程正在获取或设置值,其他线程也不能获取或设置值。然而,没有什么可以阻止的线程A读取当前值(比如2(,线程B读取相同的当前值(2(,每个线程在其private临时,然后每个线程写入其递增的值(两个线程均为3(添加到属性。所以,两个线程递增,但属性没有从2变为4;它只从2至3。您需要执行整个增量操作(get,increment私有值,set(,这样其他线程就不能在属性进行过程中读取或写入该属性。

最新更新