Как обнаружить и сломать бесконечное l oop в Unity - PullRequest
0 голосов
/ 07 января 2020

Я работаю над большой игрой в Unity, и один из моих методов иногда превращается в бесконечное l oop. Например, это может быть код, который я использую:

public void veryBigMethod(int n) {

    if (n % 2 == 0) {
        while (true) {
            // do a lot of work here
            // that might lead to an infinite loop
        }
    }
    else {
        // much shorter code that never fails
    }
}

Я пробовал это решение, но оно не работает:

public void runLoopNeverStuck() {
    Thread t = new Thread(veryBigMethod);
    t.Start();
    if (!t.Join(TimeSpan.FromSeconds(30))) {
        t.Abort();
        throw new Exception("More than 30 secs.");
    }
}

Что мне делать, используя только код обнаружить такой al oop и остановить его?

Почему мой код выше не работает на Unity?

Важное замечание Я могу не используйте Task / asyn c в моем коде, поэтому, пожалуйста, дайте мне ответы с темами

Ответы [ 2 ]

1 голос
/ 07 января 2020

Вы можете использовать токены отмены, чтобы прервать задание после того, как истекло желаемое время ожидания. Например:

bool timedOut;
CancellationToken ct;

private IEnumerator PerformTimedAction(Action action, int timeout = 5)
{
    CancellationTokenSource cts = new CancellationTokenSource();
    ct = cts.Token;

    Coroutine timeoutCoroutine = StartCoroutine(TimeoutChecker(timeout));
    var t = Task.Run(action, ct);
    yield return new WaitWhile(() => t.Status != TaskStatus.RanToCompletion && !timedOut);

    if (timedOut)
    {
        cts.Cancel();
        Debug.Log("Task timed out");
    }            
    else
    {
        StopCoroutine(timeoutCoroutine);
        Debug.Log("Task successfully completed");
    }   
}

private IEnumerator TimeoutChecker(float timeout)
{
    timedOut = false;
    while (timeout > 0)
    {
        timeout -= Time.deltaTime;
        yield return null;
    }
    timedOut = true;
}

Предполагая, что у нас есть следующая бесконечная задача:

private void MyEndlessTask()
{
    while (true)
    {
        ct.ThrowIfCancellationRequested();
        Debug.Log("Running");
    }
}

При следующем использовании задача будет выполнена до конца, иначе она превысит заданное по умолчанию 5 секунд:

StartCoroutine(PerformTimedAction(MyEndlessTask));
0 голосов
/ 07 января 2020

Вы можете создать объект таймера и обновить значение идентификатора на elasped.

bool stopLoop = false;

System.Timers.Timer timer = new System.Timers.Timer();
timer.Interval = TimeSpan.FromSeconds(30);
timer.Elapsed += (s, e) => stopLoop = true;
timer.Start();

Теперь проверьте наличие идентификатора stopLoop в вашем l oop и установите его значение, если оно установлено на true* 1006. *

public void veryBigMethod(int n) {

    if (n % 2 == 0) {
        while (true) {
            // do a lot of work here
            // that might lead to infinite loop

            if (stopLoop) {
               break;
            }
        }
    }
    else {
        // much shorter code the never fails
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...