4

我正在使用 Unity3D 和 Mono 制作多人在线游戏。语言是 C# 脚本。我知道 Unity 不是线程安全的。Mono 中的 C# 允许您使用System.Threading创建新线程。但是 Unity 会禁止新线程修改任何GameObjects

在我的代码中,我启动了一个新线程来等待来自我的一些本机 C 代码(作为插件合并到 Unity 中)的回调。这样,当回调被调用时,它将在新线程上,而不是 Unity 有权操作 GameObjects 的主线程。但是,我希望修改游戏对象。我该怎么办?我应该使用主线程来轮询新线程吗?或者有没有更好的解决方案?

4

1 回答 1

10

有不止一种方法可以向主线程发出第二个线程上可用数据的信号。一般来说,第一种方法可能是让第一个线程“阻塞”(等待)直到第二个线程“发出信号”;但是,这里不做详细介绍,这不是您想要采用的方法,因为在您在第二个线程上执行冗长的计算时阻塞主线程将使您的游戏在最坏的情况下无响应或在最好的情况下变得紧张。

所以这留下了您提出的另一种方法:轮询。无论您是否经常觉得有必要(每帧一次,每 60 帧一次),您的主线程代码(例如在 MonoBehaviour 中)都会想要检查第二个线程中的任务状态。这可以通过调用方法或检查第二个线程“拥有”的对象上的布尔值来实现。通过这种方法,您的任务将指示主线程轮询事情是“完成”还是“未完成”。Unity co-routines 可能是从主线程实现轮询逻辑的有用机制。

但是,您不一定已经完成。如果您的第二个线程将重复生成新数据到同一个变量或缓冲区中,您还必须确保您的主线程不会同时从您的第二个线程正在写入的缓冲区中读取。对于少量数据,当新数据准备好时,您可以使用双缓冲方法(两个缓冲区/变量,一个用于读取,一个用于写入,通过指针/引用交换进行交换);或者您可以使用 C# 锁(但这可能会阻塞您的主线程并产生前面描述的副作用)。

一旦您的主线程获得所需的数据,您当然可以继续从主线程修改您的游戏对象。

请注意,您的问题并不是 Unity 特有的。大多数 UI 框架都有这个限制(有充分的理由),并且线程之间的通信在每个实例中都以类似的方式解决。

于 2013-01-28T01:49:56.397 回答