简而言之:
我有一个计数器变量,可以从许多线程访问。尽管我已经实现了多线程读/写保护,但该变量似乎仍然(以一种不一致的方式)被同时写入,从而导致计数器的结果不正确。
进入杂草:
我使用的是“ 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,这会影响代码的其他部分。此错误不一致地发生。
这是我用于计数器变量的多线程保护:
//用于同步数据访问文件的后台队列 globalBackgroundSyncronizeDataQueue = DispatchQueue(标签: “ globalBackgroundSyncronizeSharedData”)
var numberOfFeedsToFetch_Value: Int = 0 var numberOfFeedsToFetch: Int { set (newValue) { globalBackgroundSyncronizeDataQueue.sync() { self.numberOfFeedsToFetch_Value = newValue } } get { return globalBackgroundSyncronizeDataQueue.sync { numberOfFeedsToFetch_Value } } }
我认为我可能会丢失一些东西,但是我使用了概要分析,而且一切似乎都很好,还检查了文档,并且我似乎正在按照他们的建议进行操作。非常感谢您的帮助。
谢谢!
答案 0 :(得分:0)
Apple论坛的答案:https://forums.developer.apple.com/message/322332#322332:
单个访问器是线程安全的,但是可以进行增量操作 鉴于您如何编写代码,这不是原子的。也就是说,当一个 线程正在获取或设置值,其他线程也不能 获取或设置值。但是,没有什么可以防止的 线程A读取当前值(例如2),线程B读取当前值 相同的当前值(2),每个线程在其当前值中加一个 私有临时,然后每个线程将其递增 属性的值(两个线程均为3)。因此,两个线程 增加,但属性未从2变为4;它只是从 2至3。您需要执行整个增量操作(获取,增量 私有值,以原子方式设置,这样其他线程就无法 正在读取或写入属性。