具有并发调度组的线程安全读/写数组访问[重复]

Posted

技术标签:

【中文标题】具有并发调度组的线程安全读/写数组访问[重复]【英文标题】:Thread Safe Read/Write Array access with Concurrent Dispatch Group [duplicate] 【发布时间】:2017-12-21 14:00:12 【问题描述】:

我正在开发一个照片编辑应用程序。我为我的用户提供了将多个资产导入到编辑 View Controller 的选项。我正在为所有“PHAsset->Asset fetching”调用创建一个Dispatch Group。 每次调用PHAsset获取请求完成块时,我需要将append获取的资产转换为Mutable Array,并更新UI(1/3导入| 2/3导入等等)的数量导入的资产。 因为 Swift Mutable Arrays 不是线程安全的,所以有时我会崩溃。我猜是从多个线程调用的完成处理程序,导致某种死锁。

使用并发调度组处理线程安全读/写数组访问的正确方法是什么?

var assets = [Asset]()

func getAssetsFromPHAssets() 

    let dispatchGroup: DispatchGroup = DispatchGroup()

    for phAsset in phAssets 

        dispatchGroup.enter() // Enter group for each asset

        PHImageManager.default().requestPlayerItem(forVideo: phAsset, options: nil, resultHandler:  (item, info) in

            let asset = Asset(playerItem: item, position: 0)
            self.assets.append(asset)

            DispatchQueue.main.async 
                self.lblImport.text = "Importing \(self.assets.count)/3"
            

            dispatchGroup.leave() // Leave group
        )
    

    dispatchGroup.notify(queue: DispatchQueue.main, execute: 
            print("finished importing")
        )

【问题讨论】:

查看副本中的答案时,answer by mooney 是最好的。 @rmaddy 感谢您的回复。对他的回答的评论看起来对他的解决方案持怀疑态度。你能确认他的回答吗 我实际上并没有测试它,但该方法正是您所需要的。创建并发队列。使用常规同步/异步从您的阵列读取,并使用屏障同步/异步写入阵列。这允许多个并发读取器,但确保写入是自己完成的,并阻止并发读取或写入。 @rmaddy 谢谢,我已经实现了您链接的答案。现在我需要考虑如何测试它大声笑。一个小问题,dispatchGroup.leave() 是否应该在当前位置,或者我也应该将它包装在 async/sync 调用中? 您可以拨打leave。无需将调用移动到更新标签的同一块内的leave 【参考方案1】:

我建议在主线程中添加新资产:

let asset = Asset(playerItem: item, position: 0)

DispatchQueue.main.async 
    self.assets.append(asset)
    self.lblImport.text = "Importing \(self.assets.count)/3"

也许 - 但这取决于您在 notify 闭包中所做的事情 - 您还应该将 dispatchGroup.leave() 调用移到主队列中。

【讨论】:

以上是关于具有并发调度组的线程安全读/写数组访问[重复]的主要内容,如果未能解决你的问题,请参考以下文章

多线程如何并发访问SQLite数据库

那些年读过的书《Java并发编程实战》构建线程安全类和并发应用程序的基础

java多线程访问同一个数组,存在并发问题吗,每个线程访问的是数组的不同部分,不存在冲突

Java 并发编程一文读懂线程协程守护线程

CopyOnWriteArrayList集合线程安全解释

死磕 java同步系列之ReentrantReadWriteLock源码解析