我刚刚在学习Swift,并在研究Grand Central Dispatch(GCD(以完成一些CPU密集型任务。以下是(我相信(我感到困惑的所有相关代码:
// global declarations
var digits = [Int]() // where the square's digits reside
var perm_q = [[Int]]() // where we accumulate permutations to check later
Let perm_q_max = 1000 // how many permutations we queue before checking them
var enq_count = 0 // how many times we've called check_squares
var N = 3 // size of N x N square
let work_q = DispatchQueue.global() // returns a global, concurrent dispatch queue
let work_g = DispatchGroup() // returns a group we put all our work into
// func which is enqueued onto a GCD queue
func check_squares( cnt: Int, perm_ary: [[Int]]) { ... }
// func which calls enqueues check_squares() onto global GCD queue
func permute( k: Int, ary: inout [Int]) {
if k == 1 {
perm_q.append( ary) // queue up this permutation for later magic checking
// if we've queued up enough permutations, then dispatch check_squares()
if ( perm_q.count >= perm_q_max) {
enq_count += 1
// --> let p: [[Int]] = perm_q // make a local copy
work_q.async( group: work_g) { // assign work all to one group
check_squares( cnt: enq_count, // check to see if any square is magic
perm_ary: p)
}
perm_q = [[Int]]() // clear out previous permutations
}
}
else { ... }
}
// main
digits = Array( 1 ... ( N * N)) // fill digits with digits 1...N^2
permute( k: digits.count, ary: &digits) // creates permutations and checks for magic squares
我遇到的问题是,除非我在permute((中取消注释work_q.async((上方的行,否则当check_squares((启动时,ary的元素为零,而我预计它有1000个元素。在我将check_squres((排入全局异步队列上的GCD之后,我立即执行perm_q=[Int],它清空数组perm_q以准备收集接下来的1000个元素。
我猜在启动check_squares((和清空perm_q之间存在竞争条件,并且清空发生在check_squares((开始之前,但我很困惑为什么会发生这种竞争。我知道调用check_squares((会生成perm_q的副本。
我想到的一个解释是,直到GCD开始执行check_squares((,perm_q才会复制到check_squares((的参数中。当这种情况发生时,perm_q已经被清空。这是在perm_q复制到ary时发生的,而不是在check_squares排队时发生的吗?将全局var perm_q的本地副本复制到permute((的本地var p中,并在排队期间将p传递给check_squares((,这会使本地var p保持不变,因为队列中来自check_squares((的引用即使在permute(退出后也不会使数组p消失。这听起来对吗?
除了将perm_q的本地副本制作成p之外,还有一种更可取的方法来处理这个问题吗?
谢谢Eric
除了制作本地副本。。。,有没有一种更可取的处理方法?
给另一个线程自己的本地副本的最简单方法是通过捕获列表:
queue.async(group: group).async { [array] in
checkSquares(array)
}