When.BarrierQueue
MontakOleg opened this issue · 5 comments
Hello! I found what barrier queue is concurrent:
Functions.swift:
let barrierQueue = DispatchQueue(label: "When.BarrierQueue", attributes: DispatchQueue.Attributes.concurrent)
But it must be serial
to behave as real barrier
. Misprint?
Yeah, I think concurrentQueue
would be more appropriate name in this case. Because in order to use concurrent queue with barrier we use flags like concurrentQueue.async(flags: .barrier)
. But as I see this constant is not even used anywhere in code, so I might end up removing it. Good catch anyway @MontakOleg 👍
This queue used in when()
function (https://github.com/vadymmarkov/When/blob/master/Sources/When/Functions.swift#L30) to synchronize access to resolved
counter.
So now with concurrent queue access is not synchronized.
Try run this test:
override func spec() {
it("resolves the promise") {
let promises: [Promise<Int>] = (0..<100000).map { _ in
let promise = Promise<Int>(queue: DispatchQueue.global(), { resolve in
// +3 needed to avoid https://github.com/vadymmarkov/When/issues/27 issue
DispatchQueue.global().asyncAfter(deadline: DispatchTime.now() + 3) {
resolve(1)
}
})
return promise
}
let doneExpectation = self.expectation(description: "Done expectation")
when(promises)
.done({ result in
doneExpectation.fulfill()
})
self.waitForExpectations(timeout: 5.0, handler:nil)
}
}
It fails. But if you change
let barrierQueue = DispatchQueue(label: "When.BarrierQueue", attributes: DispatchQueue.Attributes.concurrent)
to
let barrierQueue = DispatchQueue(label: "When.BarrierQueue")
test will success.
@MontakOleg It makes sense I guess. How about if we change barrierQueue.sync(flags: .barrier)
in https://github.com/vadymmarkov/When/blob/master/Sources/When/Functions.swift#L30
Yeah, if we add flags: .barrier
on
https://github.com/vadymmarkov/When/blob/master/Sources/When/Functions.swift#L30
and https://github.com/vadymmarkov/When/blob/master/Sources/When/Functions.swift#L38 it should work fine.
But if all calls to queue uses .barrier
flag there is no difference with serial queue.
.barrier
flag is useful for implementing "multi-readers, one writer" pattern: for "reader" blocks, you use queue.[a]sync
, for "writer" blocks, you use queue.[a]sync(flags: .barrier)
@MontakOleg Agree, good point 👍 Would you mind making a PR to change the queue to be not concurrent?