vadymmarkov/When

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

@vadymmarkov

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?