我正在使用Unity3D和Mono制作多人在线游戏。语言是C#脚本。我知道Unity不是线程安全的。 Mono中的C#允许您使用System.Threading创建新线程。但Unity会禁止新线程修改任何GameObjects。
在我的代码中,我启动了一个新线程,等待来自我的一些本机C代码的回调(并作为Plugins整合到Unity中)。通过这种方式,当回调被调用时,它将位于新线程上,而不是Unity的主线程,它具有操纵GameObjects的权限。但是,我希望要修改GameObjects。我该怎么办?我应该使用主线程来轮询新线程吗?或者有更好的解决方案吗?
答案 0 :(得分:10)
有一种方法可以通知主线程数据在第二个线程上可用。一般来说,第一种方式可能是让第一个线程“阻塞”(等待),直到第二个线程“发出信号”;但是,这里没有详细说明这是不你要采取的方法,因为当你在第二个线程上执行冗长的计算时阻塞主线程将使你的游戏在最坏的时候没有响应或者最好是紧张不安。
所以这留下了你提出的另一种方法:民意调查。但是,通常您觉得有必要(每帧一次,每60帧一次),您的主线程代码(例如在MonoBehaviour中)将要检查第二个线程中任务的状态。这可以通过调用方法或检查第二个线程“拥有”的对象上的布尔值。通过这种方法,您的任务将指示主线程轮询事情是“完成”还是“未完成”。 Unity协同例程可能是从主线程实现轮询逻辑的有用机制。
但是,你还没有完成。如果您的第二个线程将重复生成新数据到同一个变量或缓冲区,您还必须确保您的主线程不会从第二个线程同时写入的缓冲区中读取。对于少量数据,当新数据准备就绪时,您可以使用双缓冲方法(两个缓冲区/变量,一个用于读取,一个用于写入,通过指针/参考交换进行交换);或者您可以使用C#锁(但这可以使用前面描述的副作用阻止您的主线程。)
一旦主线程拥有所需的数据,您当然可以继续从主线程修改游戏对象。
请注意,您的问题并非特定于Unity。大多数UI框架都有这种限制(有充分的理由),并且线程之间的通信在每个实例中以类似的方式解决。