获取当前的调度队列?

And*_*rew 45 iphone objective-c dispatch grand-central-dispatch ios

我有一个方法应该支持从任何队列调用,并应该期望.它在后台线程本身运行一些代码,然后在它返回一个值的块参数时使用dispatch_get_main_queue.我不希望它强制它进入主队列,如果不是它进入方法时.有没有办法获得指向当前调度队列的指针?

ipm*_*mcc 27

随着弃用,dispatch_get_current_queue()实际上无法知道您正在执行的队列.如果您仔细阅读GCD源代码,您最终会看到这是因为"我正在执行什么队列?"这个问题可能有多个答案.(因为队列最终会定位其中一个全局队列,等等)

如果要保证将来的块在特定队列上运行,那么唯一的方法是让API接受队列作为参数以及完成块.这使调用者可以决定执行完成的位置.

如果只是知道调用者是否在主线程上就足够了,你可以+[NSThread isMainThread]用来查找.在通常情况下,在主GCD队列上执行的所有块都将在主线程上执行.(此规则的一个例外是,如果您的应用程序使用dispatch_main()代替主运行循环,您将不得不使用dispatch_get_specific和朋友确定您正在主队列上执行 - 这是一种相对罕见的情况.)更常见,请注意,并非所有在主线程上执行的代码都通过GCD在主队列上执行; GCD从属于主线程runloop.对于你的具体情况,听起来这可能就足够了.


Pal*_*lle 27

您可以使用NSOperationQueue.NSOperationQueue具有类函数NSOperationQueue,它将当前队列作为NSOperationQueue对象返回.获取可以使用的调度队列对象[NSOperationQueue currentQueue],它将您的currrent队列作为a返回[NSOperationQueue currentQueue].underlyingQueue.

斯威夫特3:

if let currentDispatch = OperationQueue.current?.underlyingQueue {
    print(currentDispatch)
}
Run Code Online (Sandbox Code Playgroud)

- 适用于主队列!

  • 我一直在玩这个,如果你的代码在一个与'NSOperationQueue`无关的GCD队列中执行,你似乎没有得到`[NSOperationQueue currentQueue]`的正确返回值.换句话说,如果我直接在GCD队列中执行一个块,并且从该块中调用`[NSOperationQueue currentQueue] .underlyingQueue`,我永远不会得到与我正在执行该块的实际队列相同的值. (11认同)
  • 这个答案具有误导性,因为它读起来似乎_应该_适用于任何情况……但事实并非如此。它仅适用于您使用“OperationQueue”的情况,如果您直接使用“DispatchQueue”,则情况并非如此。请更新您的答案以表明这一点。 (4认同)
  • 我认为@emaloney是对的.我做了一个实验,用`dispatch_sync(myqueue,^ {})`运行一个gcd任务块,`[NSOperationQueue currentQueue]`返回主队列. (2认同)

Mic*_*ann 23

您可以选择" dispatch_get_current_queue()",但iOS 6.1 SDK使用这些免责声明定义此API:

" Recommended for debugging and logging purposes only:"

" This function is deprecated and will be removed in a future release.".

这是另一个相关的问题,如果你想要面向未来的代码,可以考虑一些替代方案.

  • 这不是被弃用了吗? (2认同)

amb*_*ght 16

如果弃用,dispatch_get_current_queue()则无法直接获取指向正在运行的队列的指针,但是您可以通过调用获取当前队列的标签dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL),这确实为您提供了一些灵活性.

您可以通过比较它们的标签来检查您是否在该特定队列中,因此在您的情况下如果您不想强制它在主队列上,当您输入方法时,您可以使用以下标志:

let isOnMainQueue = (dispatch_queue_get_label(dispatch_get_main_queue()) == dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL))
Run Code Online (Sandbox Code Playgroud)

如果您在全局队列上运行,您将恭敬地获得与其QOS类型相关联的队列标签,该类型可以是以下之一:

com.apple.root.user-interactive-qos //qos_class_t(rawValue: 33)
com.apple.root.user-initiated-qos   //qos_class_t(rawValue: 25)
com.apple.root.default-qos          //qos_class_t(rawValue: 21)  
com.apple.root.utility-qos          //qos_class_t(rawValue: 17)
com.apple.root.background-qos       //qos_class_t(rawValue: 9) 
Run Code Online (Sandbox Code Playgroud)

然后你可以使用dispatch_get_global_queue(qos_class_self(), 0)它来返回你正在运行的同一个全局队列.

但我相信Apple特别不鼓励我们将逻辑限制在我们调用的队列中,因此更好地利用它来进行独占调试.

  • 值得一提的是,在Swift 4中此方法不可用,但经过艰苦的工作,您仍然可以获得标签`extension DispatchQueue {class var currentLabel:String {return String(validatingUTF8:__dispatch_queue_get_label(nil))?“未知”}}` (2认同)

Vas*_*huk 10

基于奥列格·巴里诺夫的回答

细节

  • 斯威夫特 5.1,Xcode 11.3.1

解决方案

import Foundation

// MARK: private functionality

extension DispatchQueue {

    private struct QueueReference { weak var queue: DispatchQueue? }

    private static let key: DispatchSpecificKey<QueueReference> = {
        let key = DispatchSpecificKey<QueueReference>()
        setupSystemQueuesDetection(key: key)
        return key
    }()

    private static func _registerDetection(of queues: [DispatchQueue], key: DispatchSpecificKey<QueueReference>) {
        queues.forEach { $0.setSpecific(key: key, value: QueueReference(queue: $0)) }
    }

    private static func setupSystemQueuesDetection(key: DispatchSpecificKey<QueueReference>) {
        let queues: [DispatchQueue] = [
                                        .main,
                                        .global(qos: .background),
                                        .global(qos: .default),
                                        .global(qos: .unspecified),
                                        .global(qos: .userInitiated),
                                        .global(qos: .userInteractive),
                                        .global(qos: .utility)
                                    ]
        _registerDetection(of: queues, key: key)
    }
}

// MARK: public functionality

extension DispatchQueue {
    static func registerDetection(of queue: DispatchQueue) {
        _registerDetection(of: [queue], key: key)
    }

    static var currentQueueLabel: String? { current?.label }
    static var current: DispatchQueue? { getSpecific(key: key)?.queue }
}
Run Code Online (Sandbox Code Playgroud)

用法

检测系统队列

DispatchQueue.currentQueueLabel
DispatchQueue.current
DispatchQueue.global(qos: .default) == DispatchQueue.current
DispatchQueue.main === DispatchQueue.current
Run Code Online (Sandbox Code Playgroud)

检测自定义队列

let queue = DispatchQueue(label: "queue-sample")
DispatchQueue.registerDetection(of: queue)
if DispatchQueue.current == queue { ... }
Run Code Online (Sandbox Code Playgroud)

样本

不要忘记在此处粘贴解决方案代码。

func subTest(queue: DispatchQueue) {
    queue.async {
        print("--------------------------------------------------------")
        print("queue label: \(DispatchQueue.currentQueueLabel ?? "nil")")
        print("print DispatchQueue.current: \(String(describing: DispatchQueue.current))")
        print("print queue == DispatchQueue.current: \(queue == DispatchQueue.current)")
        print("print queue === DispatchQueue.current: \(queue === DispatchQueue.current)")
        print("DispatchQueue.main == DispatchQueue.current: \(DispatchQueue.main == DispatchQueue.current)\n")
    }
}

func test() {
    subTest(queue: DispatchQueue.main)
    sleep(1)
    subTest(queue: DispatchQueue.global(qos: .default))
    sleep(1)
    subTest(queue: DispatchQueue.global(qos: .utility))
    sleep(1)

    let queue = DispatchQueue(label: "queue-sample")
    DispatchQueue.registerDetection(of: queue)
    subTest(queue: queue)
    sleep(1)
}

test()
DispatchQueue.global(qos: .default).async {
    test()
}
Run Code Online (Sandbox Code Playgroud)

结果

--------------------------------------------------------
queue label: com.apple.root.default-qos
print DispatchQueue.current: Optional(<OS_dispatch_queue_global: com.apple.root.default-qos[0x7fff89eb47c0] = { xref = -2147483648, ref = -2147483648, sref = 1, target = [0x0], width = 0xfff, state = 0x0060000000000000, in-barrier}>)
print queue == DispatchQueue.current: true
print queue === DispatchQueue.current: true
DispatchQueue.main == DispatchQueue.current: false

--------------------------------------------------------
queue label: com.apple.root.utility-qos
print DispatchQueue.current: Optional(<OS_dispatch_queue_global: com.apple.root.utility-qos[0x7fff89eb46c0] = { xref = -2147483648, ref = -2147483648, sref = 1, target = [0x0], width = 0xfff, state = 0x0060000000000000, in-barrier}>)
print queue == DispatchQueue.current: true
print queue === DispatchQueue.current: true
DispatchQueue.main == DispatchQueue.current: false

--------------------------------------------------------
queue label: queue-sample
print DispatchQueue.current: Optional(<OS_dispatch_queue_serial: queue-sample[0x600000275780] = { xref = 7, ref = 3, sref = 2, target = com.apple.root.default-qos.overcommit[0x7fff89eb4840], width = 0x1, state = 0x0060002500000b01, enqueued, max qos 5, draining on 0xb03, in-barrier}>)
print queue == DispatchQueue.current: true
print queue === DispatchQueue.current: true
DispatchQueue.main == DispatchQueue.current: false

--------------------------------------------------------
queue label: com.apple.main-thread
print DispatchQueue.current: Optional(<OS_dispatch_queue_main: com.apple.main-thread[0x7fff89eb43c0] = { xref = -2147483648, ref = -2147483648, sref = 1, target = com.apple.root.default-qos.overcommit[0x7fff89eb4840], width = 0x1, state = 0x001ffe9000000300, dirty, in-flight = 0, thread = 0x303 }>)
print queue == DispatchQueue.current: true
print queue === DispatchQueue.current: true
DispatchQueue.main == DispatchQueue.current: true

--------------------------------------------------------
queue label: com.apple.main-thread
print DispatchQueue.current: Optional(<OS_dispatch_queue_main: com.apple.main-thread[0x7fff89eb43c0] = { xref = -2147483648, ref = -2147483648, sref = 1, target = com.apple.root.default-qos.overcommit[0x7fff89eb4840], width = 0x1, state = 0x001ffe9000000300, dirty, in-flight = 0, thread = 0x303 }>)
print queue == DispatchQueue.current: true
print queue === DispatchQueue.current: true
DispatchQueue.main == DispatchQueue.current: true

--------------------------------------------------------
queue label: com.apple.root.default-qos
print DispatchQueue.current: Optional(<OS_dispatch_queue_global: com.apple.root.default-qos[0x7fff89eb47c0] = { xref = -2147483648, ref = -2147483648, sref = 1, target = [0x0], width = 0xfff, state = 0x0060000000000000, in-barrier}>)
print queue == DispatchQueue.current: true
print queue === DispatchQueue.current: true
DispatchQueue.main == DispatchQueue.current: false

--------------------------------------------------------
queue label: com.apple.root.utility-qos
print DispatchQueue.current: Optional(<OS_dispatch_queue_global: com.apple.root.utility-qos[0x7fff89eb46c0] = { xref = -2147483648, ref = -2147483648, sref = 1, target = [0x0], width = 0xfff, state = 0x0060000000000000, in-barrier}>)
print queue == DispatchQueue.current: true
print queue === DispatchQueue.current: true
DispatchQueue.main == DispatchQueue.current: false

--------------------------------------------------------
queue label: queue-sample
print DispatchQueue.current: Optional(<OS_dispatch_queue_serial: queue-sample[0x60000027a280] = { xref = 7, ref = 3, sref = 2, target = com.apple.root.default-qos.overcommit[0x7fff89eb4840], width = 0x1, state = 0x0060002500000b01, enqueued, max qos 5, draining on 0xb03, in-barrier}>)
print queue == DispatchQueue.current: true
print queue === DispatchQueue.current: true
DispatchQueue.main == DispatchQueue.current: false
Run Code Online (Sandbox Code Playgroud)


Ole*_*nov 5

基于SQLite.swift的来源。
如果您想检查您是否在自己的特殊调度队列中:

class Worker {
    private static let queueKey = DispatchSpecificKey<Int>()
    private lazy var queueContext = unsafeBitCast(self, to: Int.self)
    private lazy var queue: DispatchQueue = {
        let value = DispatchQueue(label: "com.example.App.Worker")
        value.setSpecific(key: Worker.queueKey, value: queueContext)
        return value
    }()

    func test(x: Int) -> Int {
        return dispatchSync {
            return x > 2 ? test(x: x - 1) * x : x
        }
    }

    private func dispatchSync<T>(_ block: () throws -> T) rethrows -> T {
        if DispatchQueue.getSpecific(key: Worker.queueKey) != queueContext {
            return try queue.sync(execute: block)
        }
        return try block()
    }
}

let worker = Worker()
worker.test(x: 5)
Run Code Online (Sandbox Code Playgroud)