如何在不使用dispatch_get_current_queue()的情况下验证我正在一个给定的GCD队列上运行?

时间:2022-06-29 21:04:58

Recently, I had the need for a function that I could use to guarantee synchronous execution of a given block on a particular serial dispatch queue. There was the possibility that this shared function could be called from something already running on that queue, so I needed to check for this case in order to prevent a deadlock from a synchronous dispatch to the same queue.

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

I used code like the following to do this:

我使用了如下代码:

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

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

This function relies on the use of dispatch_get_current_queue() to determine the identity of the queue this function is running on and compares that against the target queue. If there's a match, it knows to just run the block inline without the dispatch to that queue, because the function is already running on it.

该函数依赖于使用dispatch_get_current_queue()来确定该函数正在运行的队列的标识,并将其与目标队列进行比较。如果有匹配,它知道只在不发送到该队列的情况下内联地运行块,因为函数已经在该队列上运行。

I've heard conflicting things about whether or not it was proper to use dispatch_get_current_queue() to do comparisons like this, and I see this wording in the headers:

关于是否应该使用dispatch_get_current_queue()进行类似的比较,我听到了相互矛盾的说法,我在标题中看到这样的措辞:

Recommended for debugging and logging purposes only:

仅推荐用于调试和日志记录目的:

The code must not make any assumptions about the queue returned, unless it is one of the global queues or a queue the code has itself created. The code must not assume that synchronous execution onto a queue is safe from deadlock if that queue is not the one returned by dispatch_get_current_queue().

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

Additionally, in iOS 6.0 (but not yet for Mountain Lion), the GCD headers now mark this function as being deprecated.

另外,在ios6.0(但还不是Mountain Lion)中,GCD的标头现在将这个函数标记为已弃用。

It sounds like I should not be using this function in this manner, but I'm not sure what I should use in its place. For a function like the above that targeted the main queue, I could use [NSThread isMainThread], but how can I check if I'm running on one of my custom serial queues so that I can prevent a deadlock?

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

2 个解决方案

#1


36  

Assign whatever identifier you want using dispatch_queue_set_specific(). You can then check your identifier using dispatch_get_specific().

使用dispatch_queue_set_specific()分配所需的任何标识符。然后可以使用dispatch_get_specific()检查标识符。

Remember that dispatch_get_specific() is nice because it'll start at the current queue, and then walk up the target queues if the key isn't set on the current one. This usually doesn't matter, but can be useful in some cases.

请记住,dispatch_get_specific()很好,因为它将从当前队列开始,如果没有在当前队列上设置密钥,则沿着目标队列走。这通常不重要,但在某些情况下是有用的。

#2


1  

This is a very simple solution. It is not as performant as using dispatch_queue_set_specific and dispatch_get_specific manually – I don't have the metrics on that.

这是一个非常简单的解决方案。它不像手动使用dispatch_queue_set_specific和dispatch_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;
}

#1


36  

Assign whatever identifier you want using dispatch_queue_set_specific(). You can then check your identifier using dispatch_get_specific().

使用dispatch_queue_set_specific()分配所需的任何标识符。然后可以使用dispatch_get_specific()检查标识符。

Remember that dispatch_get_specific() is nice because it'll start at the current queue, and then walk up the target queues if the key isn't set on the current one. This usually doesn't matter, but can be useful in some cases.

请记住,dispatch_get_specific()很好,因为它将从当前队列开始,如果没有在当前队列上设置密钥,则沿着目标队列走。这通常不重要,但在某些情况下是有用的。

#2


1  

This is a very simple solution. It is not as performant as using dispatch_queue_set_specific and dispatch_get_specific manually – I don't have the metrics on that.

这是一个非常简单的解决方案。它不像手动使用dispatch_queue_set_specific和dispatch_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;
}