我正在编写 Unity3D 脚本并使用网络库。当数据准备好时,库会发出事件(调用委托(delegate))。我的图书馆读取该数据并发出尝试访问 GameObject
的事件但是我得到了这些错误
CompareBaseObjectsInternal can only be called from the main thread.
Constructors and field initializers will be executed from the loading thread
when loading a scene. Don't use this function in the constructor or field
initializers, instead move initialization code to the Awake or Start function.
ArgumentException: CompareBaseObjectsInternal can only be called from the main
thread. Constructors and field initializers will be executed from the loading
thread when loading a scene. Don't use this function in the constructor or field
initializers, instead move initialization code to the Awake or Start function.
没关系。我想我明白网络消息是在一个单独的线程上处理的,Unity3D 正试图指出这一点,以及从另一个线程操作东西是如何不线程安全的。
我的问题是:推荐的处理方法是什么?
我想的不是直接在我的处理程序中调用委托(delegate),而是创建某种对象来引用事件中传递的所有参数并将它们添加到 List<MyEvent>
中。的事件。
我必须创建一个线程安全的包装类来包含该列表,该列表允许我使用锁添加和删除事件,因为 List<>
不是线程安全的。
然后我将以某种方式需要在主线程上处理这些事件。我不确定最好的方法是什么。处理网络的类是 MonoBehavior
本身所以我想我可以拥有它的Update
方法从列表中删除事件并发送它们。
这听起来是个好主意还是有其他更好或更简单的方法来实现这一目标?
最佳答案
这是我最终得到的结果。
public class EventProcessor : MonoBehaviour {
public void QueueEvent(Action action) {
lock(m_queueLock) {
m_queuedEvents.Add(action);
}
}
void Update() {
MoveQueuedEventsToExecuting();
while (m_executingEvents.Count > 0) {
Action e = m_executingEvents[0];
m_executingEvents.RemoveAt(0);
e();
}
}
private void MoveQueuedEventsToExecuting() {
lock(m_queueLock) {
while (m_queuedEvents.Count > 0) {
Action e = m_queuedEvents[0];
m_executingEvents.Add(e);
m_queuedEvents.RemoveAt(0);
}
}
}
private System.Object m_queueLock = new System.Object();
private List<Action> m_queuedEvents = new List<Action>();
private List<Action> m_executingEvents = new List<Action>();
}
其他一些类中的启动代码将其中之一添加到启动它的 GameObject。网络线程通过调用 eventProcessor.queueEvent
添加 Action,上面的 Update
函数最终在主线程上执行这些操作。我将所有操作拉到另一个队列,以尽可能少地锁定事物。
我想这并不难。我只是想知道是否还有其他推荐的解决方案。
关于c# - Unity3D,如何在正确的线程中处理事件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22513881/