我有一些我需要同步的模型类。有一个Library
类型的主要对象包含几个Album
个对象(例如,想象一个音乐库)。库和专辑都通过实现NSCoding
协议来支持序列化。我需要通过相册修改和两个类的序列化来同步对库的修改,以便我知道更新不会踩到彼此的脚趾,并且我不会在更新过程中序列化对象。
我以为我只会将所有对象传递给共享调度队列,dispatch_async
所有setter代码和dispatch_sync
getter。这很简单,但它不起作用,因为程序流是递归的:
// In the Library class
- (void) encodeWithCoder: (NSCoder*) encoder
{
dispatch_sync(queue, ^{
[encoder encodeObject:albums forKey:…];
});
}
// In the Album class, same queue as above
- (void) encodeWithCoder: (NSCoder*) encoder
{
dispatch_sync(queue, ^{
[encoder encodeObject:items forKey:…];
});
}
现在序列化库会触发相册序列化,并且由于两个方法都在同一队列上使用dispatch_sync
,因此代码会死锁。我在某处看到了这种模式:
- (void) runOnSynchronizationQueue: (dispatch_block_t) block
{
if (dispatch_get_current_queue() == queue) {
block();
} else {
dispatch_sync(queue, block);
}
}
它是否有意义,是否有效,是否安全?有没有更简单的方法来进行同步?
答案 0 :(得分:7)
有关GCD中递归锁定的说明,请参阅dispatch_async man page的递归锁定部分。简要总结一下,当发生类似这样的事情时,重新考虑对象层次结构通常是一个好主意。
一旦你重构了代码,你就可以使用dispatch_set_target_queue()
来控制执行的层次结构(在更高级别的队列中定位下级队列),这样它就是操作而不是需要控制的对象,但是这也假设你不能简单地使用完成回调来完成相同的同步效果(坦率地说,更为推荐,因为抽象队列层次结构很难概念化和调试)。
我知道这不是你想要的答案,但是你有点像“你不能从这里到达那里”GCD的情况以及对如何做事的更根本的反思“GCD方式“在这种情况下几乎肯定是必要的。