我对dispatch_queues的规则感到有点困惑。
假设我创建了一个这样的队列:
_captureSessionQueue = dispatch_queue_create("capture_session_queue", NULL);
我将AVCaptureSession
初始化为:
dispatch_async(_captureSessionQueue, ^{
self.captureSession = [self createCaptureSession];
});
我的问题是,我现在绝对要求使用
dispatch_async(_captureSessionQueue, ^{...})
每当我想访问captureSession
对象?
例如,这是不是很糟糕?
(注意我在这里使用主队列,而不是会话队列)
dispatch_async(dispatch_get_main_queue(), ^{
[self.captureSession addInput:input];
})
我必须
dispatch_async(_captureSessionQueue, ^{
[self.captureSession addInput:input];
})
还是可选的?
答案 0 :(得分:2)
这完全取决于被访问对象的线程安全性。
在您喜欢的任何队列中使用它。
您可以在不同的线程中使用它,但您必须同步访问
请勿在其他队列中使用它。
迈克·阿什的This Friday Q&A是关于这个主题的好读物。 Apple线程编程指南中还有一个(incomplete) list。
答案 1 :(得分:1)
真正的问题是你这么说的原因:
dispatch_async(_captureSessionQueue, ^{
self.captureSession = [self createCaptureSession];
});
这是因为[self createCaptureSession]
耗时吗?然后在后台线程中创建它,但将其分配给主线程上的self.captureSession
。这将使您以后的生活更轻松。基本上,如果您对self.captureSession
的所有访问都在主线程上,那么该访问将是线程安全的(并且很容易)。
所以,我想写一下(如果我理解为什么我们首先使用后台线程):
dispatch_async(_captureSessionQueue, ^{
AVCaptureSession* sess = [self createCaptureSession];
dispatch_asynch(dispatch_get_main_queue(), ^ {
self.captureSession = sess;
});
});
在背景线程中与self
的财产交谈在我看来是混乱和可能发生灾难的一种方法。 GCD的一个巨大好处是你可以避免这种事情,因为相反,你可以将东西从线程传递给线程(如上面的代码中所示)。
答案 2 :(得分:0)
您创建了一个串行队列_captureSessionQueue。您可以使用该队列来保证调度到该队列的所有块将一个接一个地执行,如在主队列上,但在后台线程上,与主队列不同。
在串行队列上调度意味着可以保证调度到队列的所有先前调用都已完成,这通常会使事情变得简单并且不需要同步。例如,在设置self.captureSession的块之后调度到_captureSessionQueue的任何内容都会发现self.captureSession已经初始化。
但是,如果你想在另一个线程上使用self.captureSession,那很好。您只是没有从串行队列获得的保证。