swift icon indicating copy to clipboard operation
swift copied to clipboard

[SR-12479] Inconsistent behavior when using DispatchQueue.sync(flags:execute:) in property getter.

Open swift-ci opened this issue 4 years ago • 2 comments

Previous ID SR-12479
Radar rdar://problem/62201587
Original Reporter kuanfajardo (JIRA User)
Type Bug

Additional Detail from JIRA
Votes 0
Component/s
Labels Bug
Assignee None
Priority Medium

md5: a00f1c1f960a76d1c8611f9999e59b4e

Issue Description:

When performing a `sync(flags:execute: )` operation in a property getter, I get the following error __only if I actually pass in any flags:

Thread 1: closure argument passed as @noescape to Objective-C has escaped: file , line 56, column 56

@propertyWrapper
public final class GCDSynchronized<Value: Any> {
  private var value: Value
  private let queue: DispatchQueue

  /* Various init methods */

  public var wrappedValue: Value {
    get {
->    queue.sync(flags: ***) { self.value }  // If *** is not [], crash!
    }
    
    /* Setter */
  }
}

It works just fine if I pass an empty array to the `flags` param, which to me is dumbfounding since it's the same method either way. Only thing I could think of is that the implementation of `sync(flags:execute)` calls `sync(execute: )` if `flags.isEmpty`, in which case my beef is with the former not handling my escaping closure 🙁

P.S. The line numbers from the error (56, 56) do not match my line numbers (which is 140).

swift-ci avatar Apr 01 '20 01:04 swift-ci

@swift-ci create

beccadax avatar Apr 17 '20 22:04 beccadax

This is still an issue with Xcode 14.3 (14E222b), though it might be restricted to .assignCurrentContext:

import Foundation

let queue = DispatchQueue(label: "I'm a train choo choo", attributes: .concurrent)

queue.sync(flags: .barrier) { print("eenie") }
queue.async(flags: .barrier) { print("meenie") }
queue.async(flags: .assignCurrentContext) { print("minie") }
queue.sync(flags: .assignCurrentContext) { print("no soup for you") }

Confirmed on both x86 and M1 with both serial and concurrent queues: closure argument passed as @noescape to Objective-C has escaped: file , line 61, column 57

For what it's worth, my behavioral expectations for queue.sync(flags: .assignCurrentContext, execute: callback) are:

  1. add intention to queue
  2. block current thread until all previously enqueued barriers are lifted
  3. resume thread to run return try callback(), potentially concurrently with other non-barrier threads (depending on queue attributes and the presence of the .barrier flag)
  4. job done, remove from queue and off to the pub

za-creature avatar Jun 08 '23 15:06 za-creature