Google Daydream Thread с Unity

Я пытаюсь использовать темы в своем проекте 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 правильно убила поток, как и ожидалось.

2 ответа

Я бы посоветовал сделать void Update Public, но очень трудно увидеть, что вы пытаетесь сделать здесь, так как мы не видим код. Вы также можете сделать цикл while с isAlive!= true. Но в зависимости от вашей программы это может быть не очень хорошей идеей.

Во-первых, используйте 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
        }
    }
}

В качестве альтернативы вы можете оставить Run-thread в ожидании, пока 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();
    }
}
Другие вопросы по тегам