使用GCD进行递归同步

zou*_*oul 4 multithreading synchronization objective-c grand-central-dispatch

我有一些我需要同步的模型类.有一个类型的主要对象Library包含几个Album对象(例如,想象一个音乐库).库和专辑都通过实现NSCoding协议来支持序列化.我需要通过相册修改和两个类的序列化来同步对库的修改,以便我知道更新不会踩到彼此的脚趾,并且我不会在更新过程中序列化对象.

我以为我只会将所有对象传递给共享调度队列,dispatch_async所有setter代码和dispatch_syncgetter.这很简单,但它不起作用,因为程序流是递归的:

// 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:…];
    });
}
Run Code Online (Sandbox Code Playgroud)

现在序列化库会触发相册序列化,并且由于两种方法都dispatch_sync在同一队列上使用,因此代码会死锁.我在某处看到过这种模式:

- (void) runOnSynchronizationQueue: (dispatch_block_t) block
{
    if (dispatch_get_current_queue() == queue) {
        block();
    } else {
        dispatch_sync(queue, block);
    }
}
Run Code Online (Sandbox Code Playgroud)

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

jkh*_*jkh 7

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

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

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