0

我正在尝试在我的 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() 函数继续循环,但 thread.IsAlive 继续声明线程处于活动状态,当我理解它已停止操作时。如果我退出该脚本正在其中运行的场景,则线程将终止并且脚本会按预期继续,但是当我留在场景中时它不会终止。我不知道为什么。

几乎与此相同的代码已经在 Windows 机器上进行了测试,在 Unity 中运行,它完全符合我的预期,这让我相信这可能是一个 Android/Daydream 问题。

在诊断发生的事情方面的任何帮助都会很棒。由于重现问题所需的代码、场景和平台的规模,很难发布 MWE(抱歉)。

更新:更改了我的 Windows 代码以更接近地复制 Android 版本。现在可以确认这是 Android/Daydream 问题,而不是“场景切换”问题。Windows 版本按预期正确杀死了线程。

4

2 回答 2

0

首先:使用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
        }
    }
}

或者,您可以让运行线程等待,直到 Update 将信号传递给它。

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();
    }
}
于 2017-06-30T11:16:51.853 回答
0

我建议将 void Update Public 设为公开,但由于我们看不到代码,因此很难看到您在此处尝试执行的操作。您也可以使用 isAlive 进行 while 循环!= true。但取决于您的程序,这可能不是一个好主意。

于 2017-06-30T08:30:33.410 回答