12

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

例如:

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

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

4

2 回答 2

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,您可能会破坏将其分派到后台的整个目的,即最小化对主队列的影响。最后一个版本缓解了这个问题。

作为最后的观察,如果你有一个串行队列(或一个非全局并发队列,你在其中使用屏障进行更新),这通常被用作一种完全不需要锁的技术,只要所有更新和查询formyID被分派到该队列。请参阅并发编程指南中的消除基于锁的代码。

于 2013-09-05T01:37:36.080 回答
4

那里的锁只会阻止同时分派两个不同的块。但是它们是异步调度的,因此它们可能会在那时执行,也可能在未来任意远的地方执行。调度调用也不会等待它们完成。

所以块内的东西是不同步的。以最小的更改实现这一目标的选项是同步调度或只是在块内@synchronizing。

根据您在做什么,最好的想法可能是建立一个串行调度队列并将您的块分派到该队列上。

于 2013-09-04T22:57:41.463 回答