40

最近,我需要一个函数来保证在特定串行调度队列上同步执行给定块。有可能这个共享函数可以从已经在该队列上运行的东西中调用,所以我需要检查这种情况,以防止同步分派到同一个队列时出现死锁。

我使用如下代码来执行此操作:

void runSynchronouslyOnVideoProcessingQueue(void (^block)(void))
{
    dispatch_queue_t videoProcessingQueue = [GPUImageOpenGLESContext sharedOpenGLESQueue];

    if (dispatch_get_current_queue() == videoProcessingQueue)
    {
        block();
    }
    else
    {
        dispatch_sync(videoProcessingQueue, block);
    }
}

此函数依赖于使用dispatch_get_current_queue()来确定运行此函数的队列的身份,并将其与目标队列进行比较。如果匹配,它知道只运行块内联而不调度到该队列,因为函数已经在其上运行。

dispatch_get_current_queue()我听说过关于使用这样的比较是否合适的相互矛盾的事情,我在标题中看到了这样的措辞:

建议仅用于调试和记录目的:

代码不得对返回的队列做出任何假设,除非它是全局队列之一或代码自己创建的队列。如果该队列不是 dispatch_get_current_queue() 返回的队列,则代码不能假定在队列上同步执行不会出现死锁。

此外,在 iOS 6.0 中(但尚不支持 Mountain Lion),GCD 标头现在将此功能标记为已弃用。

听起来我不应该以这种方式使用此功能,但我不确定应该使用什么来代替它。对于像上面这样针对主队列的函数,我可以使用[NSThread isMainThread],但是如何检查我是否在我的自定义串行队列之一上运行,以便防止死锁?

4

2 回答 2

36

分配您想要使用的任何标识符dispatch_queue_set_specific()。然后,您可以使用 . 检查您的标识符dispatch_get_specific()

请记住,这dispatch_get_specific()很好,因为它将从当前队列开始,然后如果未在当前队列上设置密钥,则沿着目标队列前进。这通常无关紧要,但在某些情况下可能很有用。

于 2012-10-09T19:09:07.893 回答
1

这是一个非常简单的解决方案。它不如使用dispatch_queue_set_specificdispatch_get_specific手动的性能好——我没有这方面的指标。

#import <libkern/OSAtomic.h>

BOOL dispatch_is_on_queue(dispatch_queue_t queue)
{
    int key;
    static int32_t incrementer;
    CFNumberRef value = CFBridgingRetain(@(OSAtomicIncrement32(&incrementer)));
    dispatch_queue_set_specific(queue, &key, value, nil);
    BOOL result = dispatch_get_specific(&key) == value;
    dispatch_queue_set_specific(queue, &key, nil, nil);
    CFRelease(value);
    return result;
}
于 2016-06-21T11:40:57.157 回答