我有一个带有一些方法的 objective-c 类,它们使用 GCD 队列来确保对资源的并发访问串行发生(执行此操作的标准方法)。
其中一些方法需要调用同一个类的其他方法。所以锁机制需要是可重入的。有没有标准的方法来做到这一点?
起初,我使用了这些方法中的每一种
dispatch_sync(my_queue, ^{
// Critical section
});
同步访问。如您所知,当这些方法中的一个调用另一个这样的方法时,会发生死锁,因为 dispatch_sync 调用会停止当前的执行,直到另一个 block 被执行,而另一个 block 也无法执行,因为队列上的执行已停止。为了解决这个问题,我使用了例如这个方法:
- (void) executeOnQueueSync:(dispatch_queue_t)queue : (void (^)(void))theBlock {
if (dispatch_get_current_queue() == queue) {
theBlock();
} else {
dispatch_sync(queue, theBlock);
}
}
在我的每一个方法中,我都使用
[self executeOnQueueSync:my_queue : ^{
// Critical section
}];
我不喜欢这个解决方案,因为对于每个具有不同返回类型的 block ,我需要编写另一个方法。此外,这个问题对我来说很常见,我认为应该有一个更好的标准解决方案。
最佳答案
首先要注意的是:dispatch_get_current_queue()
已弃用。现在的规范方法是使用 dispatch_queue_set_specific
。一个这样的例子可能是这样的:
typedef dispatch_queue_t dispatch_recursive_queue_t;
static const void * const RecursiveKey = (const void*)&RecursiveKey;
dispatch_recursive_queue_t dispatch_queue_create_recursive_serial(const char * name)
{
dispatch_queue_t queue = dispatch_queue_create(name, DISPATCH_QUEUE_SERIAL);
dispatch_queue_set_specific(queue, RecursiveKey, (__bridge void *)(queue), NULL);
return queue;
}
void dispatch_sync_recursive(dispatch_recursive_queue_t queue, dispatch_block_t block)
{
if (dispatch_get_specific(RecursiveKey) == (__bridge void *)(queue))
block();
else
dispatch_sync(queue, block);
}
这种模式非常有用,但可以说它不是万无一失的,因为您可以使用 dispatch_set_target_queue
创建嵌套的递归队列,并且尝试从内部队列中将外部队列上的工作入队会死锁,甚至尽管您已经在“锁内”(在 mock 引号中,因为它只是看起来 像一把锁,但它实际上是不同的东西:一个队列——因此是问题,对吗?)对于外部锁。 (您可以通过包装对 dispatch_set_target_queue
的调用并维护您自己的带外目标图等来解决这个问题,但这留给读者作为练习。)
你接着说:
I do not like this solution, because for every block with a different return types, I need to write another method.
这种“状态保护串行队列”模式的总体思路是保护私有(private)状态;您为什么要为此“带来自己的队列”?如果它是关于共享状态保护的多个对象,则为它们提供一种固有的方式来查找队列(即,要么在初始时间将其插入,要么将其放在所有相关方都可以相互访问的地方)。目前尚不清楚“自带队列”在这里有何用处。
关于objective-c - 如何通过GCD在objective-c中实现可重入锁机制?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19494167/