所以我有一个游戏,其中主线程执行您期望的常用更新/渲染逻辑,以及第二个执行非常强烈处理的线程。我遇到的问题是偶尔主线程将被中断,游戏将降至60FPS以下。我很确定它被其他线程阻止,但由于没有明确的锁定,我无法证明它。
有几种情况我可以想到为什么主线程会被辅助线程阻止:
我已经尝试过安装秒表并测量哪些代码区域需要时间,但这并没有真正告诉我“主线程随机停止500ms”;它实际上并没有告诉我是否有长时间阻塞主线程的锁。
我是否可以使用任何技术来缩小此问题的原因?
-----编辑-----
这些是运行Mono分析器并报告锁争用的结果:
Monitor lock summary
Lock object 0x7f05190c9fe0: 1 contentions
0.002126 secs total wait time, 0.002126 max, 0.002126 average
1 contentions from:
(wrapper runtime-invoke) object:runtime_invoke_void__this__ (object,intptr,intptr,intptr)
System.Threading.Thread:StartInternal ()
System.Threading.Timer/Scheduler:SchedulerThread ()
(wrapper unknown) System.Threading.Monitor:FastMonitorEnterV4 (object,bool&)
System.Threading.Monitor:Enter (object,bool&)
System.Threading.Monitor:TryEnter (object,int,bool&)
(wrapper managed-to-native) System.Threading.Monitor:try_enter_with_atomic_var (object,int,bool&)
Lock object 0x7f051910b100: 1 contentions
0.000628 secs total wait time, 0.000628 max, 0.000628 average
1 contentions from:
Ninject.Components.ComponentContainer:Get (System.Type)
Ninject.Components.ComponentContainer:ResolveInstance (System.Type,System.Type)
Ninject.Components.ComponentContainer:CreateNewInstance (System.Type,System.Type)
System.Reflection.ConstructorInfo:Invoke (object[])
System.Reflection.MonoCMethod:Invoke (System.Reflection.BindingFlags,System.Reflection.Binder,object[],System.Globalization.CultureInfo)
System.Reflection.MonoCMethod:DoInvoke (object,System.Reflection.BindingFlags,System.Reflection.Binder,object[],System.Globalization.CultureInfo)
System.Reflection.MonoCMethod:InternalInvoke (object,object[])
(wrapper managed-to-native) System.Reflection.MonoCMethod:InternalInvoke (System.Reflection.MonoCMethod,object,object[],System.Exception&)
(wrapper runtime-invoke) <Module>:runtime_invoke_void__this___object (object,intptr,intptr,intptr)
Ninject.Activation.Caching.ActivationCache:.ctor (Ninject.Activation.Caching.ICachePruner)
Ninject.Activation.Caching.GarbageCollectionCachePruner:Start (Ninject.Activation.Caching.IPruneable)
(wrapper remoting-invoke-with-check) System.Threading.Timer:.ctor (System.Threading.TimerCallback,object,int,int)
System.Threading.Timer:.ctor (System.Threading.TimerCallback,object,int,int)
System.Threading.Timer:Init (System.Threading.TimerCallback,object,long,long)
System.Threading.Timer:Change (long,long,bool)
System.Threading.Timer/Scheduler:Change (System.Threading.Timer,long)
(wrapper unknown) System.Threading.Monitor:FastMonitorEnterV4 (object,bool&)
System.Threading.Monitor:Enter (object,bool&)
System.Threading.Monitor:TryEnter (object,int,bool&)
(wrapper managed-to-native) System.Threading.Monitor:try_enter_with_atomic_var (object,int,bool&)
Lock object 0x7f05190ca000: 1 contentions
0.000347 secs total wait time, 0.000347 max, 0.000347 average
1 contentions from:
(wrapper runtime-invoke) object:runtime_invoke_void__this__ (object,intptr,intptr,intptr)
System.Threading.Thread:StartInternal ()
System.Threading.Timer/Scheduler:SchedulerThread ()
(wrapper remoting-invoke-with-check) System.Threading.EventWaitHandle:Reset ()
System.Threading.EventWaitHandle:Reset ()
(wrapper unknown) System.Threading.Monitor:FastMonitorEnterV4 (object,bool&)
System.Threading.Monitor:Enter (object,bool&)
System.Threading.Monitor:TryEnter (object,int,bool&)
(wrapper managed-to-native) System.Threading.Monitor:try_enter_with_atomic_var (object,int,bool&)
Lock contentions: 3
Lock acquired: 3
Lock failures: 0
这是从运行游戏大约20-30秒,在此期间我观察到至少10个滞后峰值。在那段时间内只有3个锁定争用,所有这些争用都需要不到16毫秒来解决。
答案 0 :(得分:4)
您正在使用垃圾收集平台来运行实时应用程序,从这一点来看,您不能期望有太多预测性。垃圾收集系统在空间用完时锁定所有正在运行的线程,通过使用3代“最近性”数据作为spaning树发现优化系统,从“根对象”中移动“可跨越的树”来清理悬空对象。但无论如何,主线程中存在或不存在同步都不会阻止它不时被停止。
其次,渲染在交换功能上阻塞(“以屏幕显示”,在直接的3d术语中),这是一个等待“第三个最旧的帧完成渲染,最后一个渲染命令列表被刷新,以及VSync”的函数收到信号“在它让主线程继续之前”。您可以尝试在交换呼叫周围进行分析,以检查您的驱动程序是否与锁定有关。
第三,OS调度程序,就像你提到的那样,是先发制人的,每个内核标记,在1到15ms之间,你可以得到上下文切换。如果你的Linux比内核V 3.1更新(或者等于),那么你将拥有内核构建选项FULL_DYN_TICKS,当整个系统上只有一个任务处于活动状态时,它会禁用抢先中断计时器,但是我觉得这是一种托管语言像这样的要求不太可能得到满足。 但是,500ms代表非常长的时间,33个滴答,这只有在你有33个其他任务在同一时间以相同的prirority运行完整CPU时才会发生。不太可能。
出于温度原因,你可能有硬件决定来限制你的CPU,或者就此而言,还有GPU。
您可以拥有一个共享图形卡内存和泄漏的复合桌面,这会强制驱动程序不时地在主内存中交换纹理。这种错误在Linux上发生了很多,特别是对于像“祖母绿”,“compiz”等“危险”的桌面。
检查另一个3D应用程序并查看行为,完全停止工作线程,看看它是否有助于主线程的健全性。检查小对象分配和旧对象分配。第一代垃圾收集可能很重要。
祝你好运