我正在尝试在我的Unity项目中使用线程,该项目正在部署在Android手机上,以便与Google Daydream VR系统一起使用。我遇到了一个问题,线程没有像我预期的那样死亡。
我正在创建一个如下所示的线程,并为其分配一个在"活着"时运行的函数。当发生特定操作时(在我的情况下,UDP 网络出现故障(,线程应该停止执行并死亡。但是,线程停止执行其功能,但不会死亡。
Thread thread;
private void Update()
{
if (!thread.IsAlive)
{
// Create a new thread.
}
}
public void createNewThread()
{
thread = new Thread(Run);
thread.Priority = System.Threading.ThreadPriority.BelowNormal;
thread.Start();
}
void Run()
{
// Do thread task.
}
在上面的示例中,线程被创建,并在 Run(( 中运行其任务。当操作发生时,在 Run(( 中途停止其任务,并且不会再次进入。Update(( 函数继续循环,但线程。IsAlive继续声明线程是活动的,据我了解它已停止运行。如果我退出运行此脚本的场景,线程将死亡,脚本将按预期继续,但当我留在场景中时,它不会死亡。我不知道为什么。
与此几乎相同的代码已经在Windows机器上进行了测试,在Unity中运行,并且它完全按照我的预期工作,这使我相信这可能是Android/Daydream问题。
任何有助于诊断正在发生的事情都会很棒。由于重现问题所需的代码、场景和平台的规模,很难发布 MWE(抱歉(。
更新:更改了我的Windows代码以更接近地复制Android版本。现在可以确认这是Android/Daydream问题,而不是"场景之间切换"问题。Windows版本按预期正确终止了线程。
我建议将无效更新公开,但由于我们看不到代码,因此很难看到您在这里尝试做什么。 你也可以做 while 循环与 isAlive != 真。但根据您的程序,这可能不是一个好主意。
首先:使用 IsBackground 告诉 .Net 在应用程序退出时关闭线程。
thread = new Thread(Run);
thread.Priority = System.Threading.ThreadPriority.BelowNormal;`
thread.IsBackground = true;
thread.Start();
当线程退出示例中的 Run 时,它将死亡。我不确定为什么你没有看到这个,但我建议查看 Run 中的代码是否有任何阻塞。执行此操作的一个好方法是附加Visual Studio调试器,冻结程序并转到Debug->Windows->Parallel Stacks。它将为您提供线程及其堆栈的可视化表示形式。
启动线程会产生大量开销。空闲线程几乎没有开销。从外观上看,您可以从不同的方法中受益。您基本上每次完成时都尝试重新启动线程。
using UnityEngine;
using System.Threading;
public class Test : MonoBehaviour
{
private Thread _thread;
void Start()
{
_thread = new Thread(Run);
_thread.Name = "DaydreamThread";
_thread.Priority = System.Threading.ThreadPriority.BelowNormal;
_thread.IsBackground = true;
_thread.Start();
}
private void Run()
{
try
{
// Endless loop
for (;;)
{
// Do your stuff
}
}
catch (ThreadAbortException)
{
// If you expect to do a Abort() on the thread then you want to
// ignore this exception
}
}
}
或者,您可以让运行线程等待,直到更新向其传递信号。
using UnityEngine;
using System.Threading;
public class Test : MonoBehaviour
{
private Thread _thread;
private ManualResetEvent _signal = new ManualResetEvent(false);
void Start()
{
_thread = new Thread(Run);
_thread.Name = "DaydreamThread";
_thread.Priority = System.Threading.ThreadPriority.BelowNormal;
_thread.IsBackground = true;
_thread.Start();
}
private void Run()
{
try
{
// Endless loop
for (;;)
{
// Wait for a signal to do another pass
_signal.WaitOne();
_signal.Reset();
// Do your stuff
}
}
catch (ThreadAbortException)
{
// If you expect to do a Abort() on the thread then you want to
// ignore this exception
}
}
void Update()
{
if (something)
// Signal Run-thread to do another pass
_signal.Set();
}
}