Подтвердить что ты не робот

Выключение Lua script для выхода

Как вы заканчиваете длинный Lua script?

У меня есть два потока: один запускает основную программу, а другой управляет пользователем Lua script. Мне нужно убить поток, который запускает Lua, но сначала мне нужно script выйти.

Есть ли способ принудительно выйти из script?

Я читал, что предлагаемый подход заключается в возврате исключения Lua. Однако он не гарантирует, что пользователь script когда-либо вызовет функцию api (он может находиться в замкнутом цикле занятости). Кроме того, пользователь может предотвратить ошибки, вызвавшие его script, с помощью pcall.

4b9b3361

Ответ 1

Вы можете использовать setjmp и longjump, как и внутренняя библиотека Lua. Это избавит вас от pcalls и просто отлично, без необходимости постоянной ошибки, не позволяя script пытаться обработать ваши фиктивные ошибки и все равно вывести вас из исполнения. (Я понятия не имею, насколько хорошо это играет с потоками.)

#include <stdio.h>
#include <setjmp.h>
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"

jmp_buf place;

void hook(lua_State* L, lua_Debug *ar)
{
    static int countdown = 10;
    if (countdown > 0)
    {
        --countdown;
        printf("countdown: %d!\n", countdown);
    }
    else
    {
        longjmp(place, 1);
    }
}

int main(int argc, const char *argv[])
{
    lua_State* L = luaL_newstate();
    luaL_openlibs(L);
    lua_sethook(L, hook, LUA_MASKCOUNT, 100);

    if (setjmp(place) == 0)
        luaL_dostring(L, "function test() pcall(test) print 'recursing' end pcall(test)");

    lua_close(L);
    printf("Done!");
    return 0;
}

Ответ 2

Вы можете установить переменную где-нибудь в своей программе и называть ее чем-то вроде forceQuitLuaScript. Затем вы используете крючок, описанный здесь, чтобы запускать все инструкции n. После инструкций n он запустит ваш крючок, который просто проверяет, установлен ли forceQuitLuaScript, и если он выполняет какую-либо очистку, вам нужно сделать и убить поток.

Изменить: вот дешевый пример того, как он может работать, только однопоточное. Это просто, чтобы проиллюстрировать, как вы можете обращаться с pcall и т.д.:

#include <stdlib.h>
#include "lauxlib.h"

void hook(lua_State* L, lua_Debug *ar)
{
    static int countdown = 10;
    if (countdown > 0)
    {
        --countdown;
        printf("countdown: %d!\n", countdown);
    }
    else
    {
        // From now on, as soon as a line is executed, error
        // keep erroring until you're script reaches the top
        lua_sethook(L, hook, LUA_MASKLINE, 0); 
        luaL_error(L, "");
    }
}

int main(int argc, const char *argv[])
{
    lua_State* L = luaL_newstate();
    luaL_openlibs(L);
    lua_sethook(L, hook, LUA_MASKCOUNT, 100);
    // Infinitely recurse into pcalls
    luaL_dostring(L, "function test() pcall(test) print 'recursing' end pcall(test)");
    lua_close(L);
    printf("Done!");
    return 0;
}

Ответ 3

Способ завершения script заключается в том, чтобы вызвать ошибку, вызвав error. Однако, если пользователь вызвал script через pcall, тогда эта ошибка будет обнаружена.

Ответ 4

Кажется, что вы можете завершить поток извне (из основного потока), так как lua ​​ script предоставляется пользователю, и вы не можете сигнализировать ему о выходе.

Если это не вариант, вы можете попробовать API отладки. Вы можете использовать lua_sethook, чтобы вы могли восстановить контроль, предполагая, что у вас есть способ изящно прекратить поток в hook.

Ответ 5

Я не нашел способ для чистого уничтожения потока, выполняющего длинный lua script, не полагаясь на какое-либо вмешательство самого script. Вот несколько подходов, которые я использовал в прошлом:

  • Если script работает долго, это, скорее всего, в некотором цикле. script может проверять значение некоторой глобальной переменной на каждой итерации. Установив эту переменную извне script, вы можете завершить поток.
  • Вы можете запустить поток, используя lua_resume. script может выйти с помощью yield().
  • Вы можете предоставить свою собственную реализацию pcall, которая проверяет наличие определенного типа ошибок. После этого script может вызвать ошибку() с настраиваемым типом ошибок, который ваша версия pcall могла бы отслеживать:

    function()
        local there_is_an_error = do_something()
        if (there_is_an_error) then
            error({code = 900, msg = "Custom error"})
        end
    end
    

Ответ 6

возможно бесполезно, но в lua я использую (luaplayer или PGELua), я выхожу с

os.exit() 

или

pge.exit()

Ответ 7

Если вы используете сопрограммы для запуска потоков, вы можете использовать coroutine.yield(), чтобы остановить его.

Ответ 8

сессии: уничтожить();

Используйте этот код одной строки, где вы хотите уничтожить lua script.