synchronized块和dispatch_async

时间:2013-09-04 22:54:48

标签: ios objective-c ios6 grand-central-dispatch dispatch-async

当我们在块中调用dispatch_async()时,使用@synchronized()在IOS中锁定会发生什么。

例如:

    id myID
-(void) foobar
{
    @synchronized(myID){
        dispatch_async(){ //do stuff with myID};
    }
}

在dispatch_async调用中锁是否仍然有效?或者更重要的是在dispatch_async()中使用另一个@synchronized()调用有什么缺点吗?

2 个答案:

答案 0 :(得分:10)

假设您正在尝试与后台队列中的此myID对象同步交互,那么您需要反过来,即调度块内的锁定。现在你有:

@synchronized(myID) {
    dispatch_async(queue, ^{
         // do stuff with myID
    });
}

这是同步将调度块添加到队列的过程,但同步你在后台执行的操作。我怀疑那不是你的意思。

您可能打算:

dispatch_async(queue, ^{
    @synchronized(myID) {
         // do stuff with myID
    }
});

它看起来非常相似,但导致完全不同的行为。现在,调度到后台队列的工作正在同步。

作为进一步的改进,如果这个调度块可能很慢(我认为它可能是),那么你可能想要尽可能地约束@synchronized块:

dispatch_async(queue, ^{

    // do slow stuff in preparation for interacting with `myID`

    @synchronized(myID) {
         // quickly do stuff with myID
    }

    // do anything else here
});

如果您在@synchronized块中执行了所有后台阻止,则可能无法将其分配到后台,即最小化对主队列的影响。最后一次演绎减轻了这个问题。

作为最后的观察,如果你有一个串行队列(或者你使用屏障进行更新的非全局并发队列),这通常被用作一种技术,可以完全消除对锁的需要,只要所有myID的更新和查询将分派到该队列。请参阅并发编程指南中的Eliminating Lock-Based Code

答案 1 :(得分:3)

那里的锁只会阻止一次调度两个不同的块。然而,它们是异步调度的,因此它们可以在当时执行,或者可以在将来任意执行。调度电话也不会等待他们完成。

因此块内的东西不同步。实现最小变化的选项是同步调度或仅在块内进行@synchronizing。

根据您正在做的事情,最好的想法可能是建立一个串行调度队列并将您的块分配给它。