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();
}
}