最近,我需要一个可以保证在特定串行调度队列上同步执行给定块的函数。有可能这个共享函数可以从已经在该队列上运行的东西中调用,所以我需要检查这种情况,以防止从同步调度到同一队列的死锁。
我使用以下代码执行此操作:
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()
进行比较是否合适的相互矛盾的事情,我在标题中看到了这样的措辞:
建议仅用于调试和记录目的:
代码不得对返回的队列做任何假设, 除非它是全局队列之一或代码本身的队列 创建。代码不能假设同步执行到a 如果该队列不是返回的队列,则队列是安全的死锁 dispatch_get_current_queue()。
此外,在iOS 6.0中(但尚未针对Mountain Lion),GCD标题现在将此功能标记为已弃用。
听起来我不应该以这种方式使用这个功能,但我不确定我应该在它的位置使用什么。对于像上面这样针对主队列的函数,我可以使用[NSThread isMainThread]
,但是如何检查我是否在我的一个自定义串行队列上运行以便防止死锁?
答案 0 :(得分:36)
使用dispatch_queue_set_specific()
指定您想要的任何标识符。然后,您可以使用dispatch_get_specific()
检查您的标识符。
请记住,dispatch_get_specific()
很好,因为它将从当前队列开始,然后如果当前队列中没有设置密钥则向上走。这通常无关紧要,但在某些情况下可能有用。
答案 1 :(得分:1)
这是一个非常简单的解决方案。它不像手动使用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;
}