Generic read/write locks in Swift

About 18 months ago, Mike Ash had a detailed look at locks and thread safety in Swift. I’ve been thinking a lot about threading lately because of a side project I’m working on, so I thought I’d try to build a generic version of a dispatch queue lock.

You can find it here. Parse and objc.io have good general primers on concurrency in Apple platform development.

Some caveats:

@inline(__always) func with<T>(queue: dispatch_queue_t, @autoclosure(escaping) get block: () -> T) -> T {
    assert(dispatch_queue_get_label(queue) != dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL), "Invoked dispatch_sync in a way that will deadlock")
    var result: T!
    dispatch_sync(queue) {
        result = block()
    }

    return result
}

First, the autoclosure here is marked as escaping even though it clearly ought to be non-escaping. Unfortunately, dispatch_sync’s function signature doesn’t include the @noescape marker, and thus can’t be used in this way. This appears to have been fixed in Swift 3. I think I have to mark result as force-unwrap for the same reason, but I won’t know until I get a chance to play with Swift 3.

Second, since dispatch_sync doesn’t return until the block you pass has been executed on the queue, calling in from the same queue you’re dispatching to will deadlock your program. The assert will catch some, but not all such calls. For example, it doesn’t know about target queues. It’s mainly meant for manually created queues.