可变多线程访问-损坏

时间:2018-07-18 17:12:56

标签: swift multithreading queue dispatch

简而言之:

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

进入杂草:

我使用的是“ 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. 专用全局队列
  

//用于同步数据访问文件的后台队列   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
        }
    }
}

我认为我可能会丢失一些东西,但是我使用了概要分析,而且一切似乎都很好,还检查了文档,并且我似乎正在按照他们的建议进行操作。非常感谢您的帮助。

谢谢!

1 个答案:

答案 0 :(得分:0)

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

  

单个访问器是线程安全的,但是可以进行增量操作   鉴于您如何编写代码,这不是原子的。也就是说,当一个   线程正在获取或设置值,其他线程也不能   获取或设置值。但是,没有什么可以防止的   线程A读取当前值(例如2),线程B读取当前值   相同的当前值(2),每个线程在其当前值中加一个   私有临时,然后每个线程将其递增   属性的值(两个线程均为3)。因此,两个线程   增加,但属性未从2变为4;它只是从   2至3。您需要执行整个增量操作(获取,增量   私有值,以原子方式设置,这样其他线程就无法   正在读取或写入属性。