SceneKit - 线程 - 在哪个线程上做啥?

Posted

技术标签:

【中文标题】SceneKit - 线程 - 在哪个线程上做啥?【英文标题】:SceneKit - Threads - What to do on which thread?SceneKit - 线程 - 在哪个线程上做什么? 【发布时间】:2015-10-20 09:52:50 【问题描述】:

使用SceneKit时,更新方法:

func renderer(aRenderer: SCNSceneRenderer, updateAtTime time: NSTimeInterval)    

不在主线程上调用,而是在其他线程上调用。

我应该在主线程上做什么,在这个“SceneKit 线程”上必须做什么?

我应该在哪里添加新节点/几何图形?

在哪里可以安全地修改这些对象的位置/等?

【问题讨论】:

这可能是因为 GameKit 的组件建模/循环被赋予了 DOD 效率的主线程吗? 我不确定,我目前认为他们只是将 SceneKit 的所有内容从主线程中移出,如果您想更改任何重要的内容,则必须转到主线程。跨度> 注意:我偶尔会发现这个方法在主线程上被调用。现在我的应用程序在为此目的设置的断点处暂停(在 Thread.isMainThread 测试中),并且调试导航器正在显示这一点。在 Xcode 8 上的 ios 10.2 sim 中运行。我猜这是一个 SceneKit 错误。似乎在第一次被调用时发生了百分之几的时间。 好吧,我已经很长时间没有使用SceneKit了,我也很可能不会再次使用它,因为问题太多了。但也许您可以尝试添加打印并查看它打印的内容 - 调试导航器偶尔会显示错误信息。 【参考方案1】:

问题是关于场景包的。节点/几何图形实际上并没有添加到主线程上,即使你在主线程中这样做。 Scenekit 不在主线程上渲染。更改被批处理到渲染线程。如果渲染是 UI,它不在主线程上。事实上,如果您在主线程上进行更改,您将得到错误的 exc,因为渲染线程正在尝试渲染被核化的对象。这就是为什么 removefromparent 在 Apples 香蕉游戏中的 SCNTransaction 中的原因。所以删除发生在渲染线程而不是主线程上。添加以相同的方式进行批处理。它实际上并没有添加到主线程上。

所以请注意,同时有一个渲染线程在运行。如果您在主线程上对 scene.rootnode 进行枚举,您将在渲染线程对根节点进行更改时崩溃。但由于事情发生得如此之快,它可能会非常罕见。一般来说去看看香蕉游戏,狐狸游戏,看看他们是如何使用它的。

【讨论】:

【参考方案2】:

SCNSceneRendererDelegate here 和 here 的文档似乎对线程没什么可说的,但委托显然是在辅助线程上调用的,至少在 macOS 10.11.6 上(显然是任何版本的 iOS在...上)。有人可能会合理地假设,如果这对 SceneKit 造成了任何类型的问题,那么文档现在应该已经进行了相应的修改。

Apple 的 Fox 示例代码有一个渲染器委托,它看似对场景进行了许多更改,而不考虑任何其他线程可能在做什么,并且据此可以合理地假设这样做不会造成任何问题 场景套件。 (似乎 Fox 几乎完全脱离了渲染器委托,所以也许没有理由担心多线程。)

这可能是由于 SceneKit 的自动每线程事务,如文档 here 所述。听起来好像只要在返回运行循环之前不需要可见效果,您就可以随时随地做任何您想做的事情。这是我能找到的关于 SceneKit 的唯一一个以任何实质性方式提及线程的文档。

综上所述,这可能是一个巨大的问题你自己的逻辑。好消息是您注意到您的委托在辅助线程上被调用。如果您在项目的早期没有注意到这一点,那么坏消息是您可能有很多工作要做。

线程可以通过多种方式进行同步。您可能最好使用 Apple 的 modern facilities 来执行此操作,但如果您发现自己处于困境中,您可能需要考虑使用 a variety of other, older approaches。

【讨论】:

以上是关于SceneKit - 线程 - 在哪个线程上做啥?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 SceneKit 的渲染队列中处理触摸事件

在 SceneKit 中使用 GIFU 库播放 GIF 会导致应用程序 UI 冻结任何解决方案? UIView Animated 从后台线程调用

gcc 在这里做啥来为每个线程运行一次此代码?

在-init,-viewdidload,-viewdidappear,-viewdiddisapper上做啥[关闭]

线程可以做啥,而基于任务的异步模式(TAP)和任务并行(TPL)与任务(或任务<T>)不能做啥?

std::thread.join() 做啥?