使用GCD进行递归同步

时间:2012-02-17 10:03:21

标签: objective-c multithreading synchronization grand-central-dispatch

我有一些我需要同步的模型类。有一个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);
    }
}

它是否有意义,是否有效,是否安全?有没有更简单的方法来进行同步?

1 个答案:

答案 0 :(得分:7)

有关GCD中递归锁定的说明,请参阅dispatch_async man page递归锁定部分。简要总结一下,当发生类似这样的事情时,重新考虑对象层次结构通常是一个好主意。

一旦你重构了代码,你就可以使用dispatch_set_target_queue()来控制执行的层次结构(在更高级别的队列中定位下级队列),这样它就是操作而不是需要控制的对象,但是这也假设你不能简单地使用完成回调来完成相同的同步效果(坦率地说,更为推荐,因为抽象队列层次结构很难概念化和调试)。

我知道这不是你想要的答案,但是你有点像“你不能从这里到达那里”GCD的情况以及对如何做事的更根本的反思“GCD方式“在这种情况下几乎肯定是必要的。