对使用 GCD 时何时将 vars 复制到 func params 感到困惑

Puzzled by when copy of vars to func params happens when using GCD

我正在学习 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 在我期望的时候有零个元素有 1,000 个元素。在我将 check_squres() 加入全局异步队列中的 GCD 之后,我执行 perm_q = [Int] 清空数组 perm_q 以准备收集接下来的 1,000 个元素。

我猜在开始 check_squares() 和清空 perm_q 之间存在竞争条件,清空发生在 check_squares() 开始之前,但我很困惑至于为什么会发生这场比赛。我知道调用 check_squares() 会复制 perm_q.

我想到的一个解释是,在 GCD 开始执行 check_squares() 之前,perm_q 到 check_squares() 的参数的复制不会发生。发生这种情况时,perm_q 已被清空。是当 perm_q 复制到 ary 时发生而不是 check_squares 入队时?将全局变量 perm_q 的本地副本制作成 permute() 的本地变量 p 并在入队期间将 p 传递给 check_squares() 使得本地变量 p 自 check_squares( ) 在队列中保持数组 p 即使在 permute() 退出后也不会消失。这听起来对吗?

除了将 perm_q 的本地副本制作成 p 之外,还有更好的处理方法吗?

谢谢,埃里克

Other than making the local copy ..., is there a preferred method of handing this?

为其他线程提供自己的本地副本的最简单方法是通过捕获列表:

queue.async(group: group).async { [array] in
    checkSquares(array)
}