在Grand Central Dispatch中使用dispatch_sync


Answers:


78

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

这样的一个例子是您使用调度队列而不是使用锁进行同步的模式。例如,假设您有一个共享的NSMutableArray a,访问权限由dispatch queue介导q。后台线程可能正在追加到数组(异步),而前台线程正在(同步)提取第一项:


1
我会对此进行+1,因为从技术上讲这是正确的,尽管我在同一队列中先做一个dispatch_async后跟一个并没有多大价值dispatch_sync。但是,当您想在另一个队列上生成多个并发作业,然后等待所有这些作业时,此相同模式很有用。
kperryua 2011年

谢谢。这开始变得有意义。如果我想使用dispatch_apply启动多个并发线程,这些线程以相互排斥的方式访问单个资源。如何使用GCD执行此操作?唯一的方法是在我的dispatch_apply中使用带有串行队列的dispatch_async吗?有没有办法使用dispatch_sync?
Rasputin Jones

@kperryua-对不起,如果示例不清楚,我们的想法是,一个单独的线程将对队列执行多个dispatch_async
David Gelhar 2011年

@David Gelhar-没问题。仅提及其他来访者。
kperryua 2011年

9
我也想像它与使用-performSelector:onThread:withObject:waitUntilDone:performSelectorOnMainThread:withObject:waitUntilDone:设置waitUntilDone为YES相似。
布拉德·拉尔森

78

首先了解它的兄弟 dispatch_async

您用于dispatch_async创建新线程。当您这样做时,当前线程将不会停止。那意味着//Do More Stuff可能在执行之前//Do something else完成

如果您希望当前线程停止,该怎么办?

您根本不使用调度。只需正常编写代码

现在,假设您想在一个不同的线程上执行某项操作,但又要等待,并确保诸如此类的操作是连续进行的

这样做有很多原因。例如,UI更新是在主线程上完成的。

那就是你使用的地方 dispatch_sync

在这里//Do something //Do something else//Do More stuff即使//Do something else在不同的线程上完成,也可以连续完成。

通常,当人们使用不同的线程时,整个目的是使某些事情无需等待就可以执行。假设您要下载大量数据,但要保持UI流畅。

因此,很少使用dispatch_sync。但它在那里。我个人从未使用过。为什么不要求提供一些确实使用dispatch_sync的示例代码或项目。


谢谢,这对我来说是一个很好的答案。使用的一个示例dispatch_sync是在另一个异步过程中用作回调。例如,Core Data的NSManagedObjectContextperformBlock方法可以在块末尾将其用作回调。
abc123 2013年

16
作为GCD初学者,我发现这句话令人误解:“您使用dispatch_async创建了一个新线程”。从到目前为止我对GCD的了解来看,调用dispatch_async不一定会创建一个新线程。我猜系统将处理线程创建或归因于每个排队任务的任务。
Aurelien Porte

实际上,我现在经常使用它。我可以在后台线程中执行代码,并向主线程执行dispatch_sync。
user4951 2013年

这太棒了-现在真的很明白。谢谢!
darkheartfelt 2014年

1
除了注释中指出的明显的小错误外,该解释也非常清楚和有用,谢谢!
Ixx

26

dispatch_sync在语义上等效于传统的互斥锁。

与...相同


2
对于串行队列,这是正确的,但对于并发队列,我们​​应将dispatch_barrier_async用于写操作,将dispatch_sync用于读操作。
Parag Bafna 2014年

4

David Gelhar没说他的示例将起作用,因为他默默地创建了串行队列(在dispatch_queue_create中传递NULL等于DISPATCH_QUEUE_SERIAL)。

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

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


3

如果您想要一些实际使用的样本,请查看我的这个问题:

我该如何解决偶尔发生的这种僵局?

我通过确保在主线程上创建主ManagedObjectContext来解决此问题。这个过程非常快,我不介意等待。不等待就意味着我将不得不处理很多并发问题。

我需要dispatch_sync,因为需要在主线程上完成一些代码,该主线程与正在执行代码的线程不同。

因此,基本上,如果您希望代码为1.像往常一样进行。您不想担心比赛条件。您想确保代码在继续之前已经完成。2.在其他线程上完成

使用dispatch_sync。

如果违反1,请使用dispatch_async。如果违反了2,则像往常一样编写代码。

到目前为止,我只执行一次,即需要在主线程上执行某些操作时。

所以这是代码:


2

dispatch_sync主要用于dispatch_async块内部,以对主线程执行某些操作(如update ui)。


0

这是一个现实的例子。您有2000个要并行分析的zip文件。但是zip库不是线程安全的。因此,所有涉及zip库的工作都将进入unzipQueue队列。(该示例在Ruby中,但是所有调用都直接映射到C库。例如,“ apply”映射到dispatch_apply(3)


9
如果您想解释一些内容,请使用伪代码。Ruby等人太具体且太高级。
Matt Melton 2012年

-1

我在异步调度内部使用调度同步来将UI更改发回主线程。

我的异步块只保留了一点,我知道主线程知道UI更改并将采取措施。通常在需要一些CPU时间的代码处理块中使用它,但是我仍然想从该块内操作UI更改。我认为,在异步块中操作UI更改是无用的,因为UI运行在主线程上。同样将它们作为辅助异步块或自委托操作,会导致UI在几秒钟后才看到它们,并且看上去很迟。

示例块:

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.