SimplGy SimplGy - 3 months ago 15
Swift Question

Should a `.barrier` on a concurrent queue become active immediately?

I'm not sure if this broke in xcode8 beta 5. Look at this code. Do you think it should print "A" first, or "B" first?

let q = DispatchQueue(label: "q", attributes: .concurrent)
q.async(flags: .barrier) {
Thread.sleep(forTimeInterval: 0.25)
print("A")
}
q.sync {
print("B")
}


Because of the
.barrier
, I think it should block the concurrent queue and print "A", "B", but it does not in the latest xcode beta.

Bug? Misunderstanding of .barrier? What do you think?

please note: I know this would print in the expected order if I used a serial queue--this is a tiny part of a much larger system and I need to understand this behavior in isolation.

Rob Rob
Answer

This was a bug fixed in beta 6.

In beta 5, not only does it not behave the way you'd expect, but the .onQueueAsBarrier precondition fails, too. The problem would appear to be buried in async with the .barrier option, because if you perform it via equivalent Objective-C API, dispatch_barrier_async, it works fine, e.g.:

let q = DispatchQueue(label: "q", attributes: .concurrent)

BarrierExperiment.dispatchBarrierAsync(q) {
    dispatchPrecondition(condition: .onQueueAsBarrier(q))
    Thread.sleep(forTimeInterval: 0.25)
    print("A")
}

q.async() {
    print("B")
}

Where

@interface BarrierExperiment : NSObject

+ (void)dispatchBarrierAsync:(dispatch_queue_t)queue block:(void (^)())block;

@end

@implementation BarrierExperiment

+ (void)dispatchBarrierAsync:(dispatch_queue_t)queue block:(void (^)())block {
    dispatch_barrier_async(queue, block);
}

@end