在Grand Central Dispatch中使用dispatch_sync

Ras*_*nes 74 cocoa grand-central-dispatch ios4 ios

任何人都可以是很清楚的用例解释的目的dispatch_syncGCD为?我无法理解我必须使用它的地点和原因.

谢谢!

Dav*_*har 77

当您想要执行块并等待结果时,可以使用它.

其中一个示例是您使用调度队列而不是锁来进行同步的模式.例如,假设您有一个共享的NSMutableArray a,其访问由调度队列调解q.后台线程可能会附加到数组(异步),而前台线程正在关闭第一个项目(同步):

NSMutableArray *a = [[NSMutableArray alloc] init];
// All access to `a` is via this dispatch queue!
dispatch_queue_t q = dispatch_queue_create("com.foo.samplequeue", NULL);

dispatch_async(q, ^{ [a addObject:something]; }); // append to array, non-blocking

__block Something *first = nil;            // "__block" to make results from block available
dispatch_sync(q, ^{                        // note that these 3 statements...
        if ([a count] > 0) {               // ...are all executed together...
             first = [a objectAtIndex:0];  // ...as part of a single block...
             [a removeObjectAtIndex:0];    // ...to ensure consistent results
        }
});
Run Code Online (Sandbox Code Playgroud)

  • 我还想把它看成类似于使用`-performSelector:onThread:withObject:waitUntilDone:`或`performSelectorOnMainThread:withObject:waitUntilDone:`并将`waitUntilDone`设置为YES. (9认同)

use*_*951 77

先了解它的兄弟 dispatch_async

//Do something
dispatch_async(queue, ^{
    //Do something else
});
//Do More Stuff
Run Code Online (Sandbox Code Playgroud)

dispatch_async用来创建一个新线程.当你这样做时,当前线程不会停止.这意味着//Do More Stuff可以在//Do something else完成之前执行

如果你想让当前线程停止会发生什么?

你根本不使用派遣.只需正常编写代码即可

//Do something
//Do something else
//Do More Stuff
Run Code Online (Sandbox Code Playgroud)

现在,假设你想在一个不同的线程上做一些事情,然后等待并确保连续完成这些事情.

有很多理由这样做.例如,UI更新是在主线程上完成的.

这就是你使用的地方 dispatch_sync

//Do something
dispatch_sync(queue, ^{
    //Do something else
});
//Do More Stuff
Run Code Online (Sandbox Code Playgroud)

在这里,你得到了//Do something //Do something else,并//Do More stuff连续完成,即使//Do something else在不同的线程完成.

通常,当人们使用不同的线程时,整个目的是让某些东西可以在不等待的情况下执行.假设您要下载大量数据,但希望保持UI流畅.

因此,很少使用dispatch_sync.但它就在那里.我个人从未使用过.为什么不要求使用dispatch_sync的示例代码或项目.

  • 作为一名GCD初学者,我发现这句话具有误导性:"你使用dispatch_async创建一个新线程".根据我对GCD的理解,调用dispatch_async不一定会创建新线程.系统将处理线程创建或归因于我猜测的每个排队任务. (16认同)

Cat*_*Man 25

dispatch_sync在语义上等同于传统的互斥锁.

dispatch_sync(queue, ^{
    //access shared resource
});
Run Code Online (Sandbox Code Playgroud)

与...一样的工作

pthread_mutex_lock(&lock);
//access shared resource
pthread_mutex_unlock(&lock);
Run Code Online (Sandbox Code Playgroud)

  • 对于串行队列也是如此,但对于并发队列,我们​​应该使用dispatch_barrier_async进行写操作,使用dispatch_sync进行读操作. (2认同)

Krz*_*oda 5

David Gelhar没有说他的示例之所以有效,只是因为他悄悄创建了串行队列(在dispatch_queue_create 中传递了 NULL,等于 DISPATCH_QUEUE_SERIAL)。

如果你希望创建并发队列(以获得所有多线程能力),他的代码将导致崩溃,因为 NSArray 突变(addObject:) 在突变(removeObjectAtIndex:) 期间甚至访问错误(NSArray 范围超出界限)。在这种情况下,我们应该使用屏障来确保两个块运行时对 NSArray 的独占访问。它不仅在运行时排除对 NSArray 的所有其他写入,而且还排除所有其他读取,从而使修改安全。

并发队列的示例应如下所示:

NSMutableArray *a = [[NSMutableArray alloc] init];
// All access to `a` is via this concurrent dispatch queue!
dispatch_queue_t q = dispatch_queue_create("com.foo.samplequeue", DISPATCH_QUEUE_CONCURRENT);

// append to array concurrently but safely and don't wait for block completion
dispatch_barrier_async(q, ^{ [a addObject:something]; }); 

__block Something *first = nil;
// pop 'Something first' from array concurrently and safely but wait for block completion...
dispatch_barrier_sync(q, ^{                        
        if ([a count] > 0) {               
             first = [a objectAtIndex:0];  
             [a removeObjectAtIndex:0];    
        }
});
// ... then here you get your 'first = [a objectAtIndex:0];' due to synchronised dispatch.
// If you use async instead of sync here, then first will be nil.
Run Code Online (Sandbox Code Playgroud)