Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/lua/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
强制Lua脚本退出_Lua - Fatal编程技术网

强制Lua脚本退出

强制Lua脚本退出,lua,Lua,如何结束长时间运行的Lua脚本 我有两个线程,一个运行主程序,另一个控制用户提供的Lua脚本。我需要杀死运行Lua的线程,但首先我需要退出脚本 有没有办法强制脚本退出 我已经读到,建议的方法是返回Lua异常。但是,不能保证用户的脚本会调用api函数(它可能处于繁忙的循环中)。此外,用户可以通过使用pcall防止错误导致脚本退出。结束脚本的方法是通过调用error引发错误。但是,如果用户已通过pcall调用脚本,则将捕获此错误。由于lua脚本是用户提供的,您无法发出退出信号,因此您似乎可以从外部(

如何结束长时间运行的Lua脚本

我有两个线程,一个运行主程序,另一个控制用户提供的Lua脚本。我需要杀死运行Lua的线程,但首先我需要退出脚本

有没有办法强制脚本退出


我已经读到,建议的方法是返回Lua异常。但是,不能保证用户的脚本会调用api函数(它可能处于繁忙的循环中)。此外,用户可以通过使用
pcall
防止错误导致脚本退出。结束脚本的方法是通过调用
error
引发错误。但是,如果用户已通过
pcall
调用脚本,则将捕获此错误。

由于lua脚本是用户提供的,您无法发出退出信号,因此您似乎可以从外部(从主线程)终止线程


如果这不是一个选项,您可以尝试调试API。您可以使用
lua\u sethook
来重新获得控制权,前提是您有一种方法可以在钩子中优雅地终止线程。

如果您使用协程来启动线程,您可以使用
coroutine.yield()
停止它。

您可以在程序中的某个地方设置一个变量,并将其称为类似于
forceQuitLuaScript的东西。然后,您将使用一个钩子来运行每个
n
指令。在
n
指令之后,它将运行钩子,只检查
forceQuitLuaScript
是否已设置,以及是否需要执行任何清理并终止线程

编辑:这里有一个关于它如何工作的廉价示例,只有这是单线程的。这只是为了说明您可能如何处理pcall等:

#包括
#包括“lauxlib.h”
void hook(lua_State*L,lua_Debug*ar)
{
静态整数倒计时=10;
如果(倒计时>0)
{
--倒计时;
printf(“倒计时:%d!\n”,倒计时);
}
其他的
{
//从现在起,只要执行一行,就会出现错误
//不断出错,直到脚本到达顶部
lua_sethook(L,hook,lua_MASKLINE,0);
luaL_错误(L,“”);
}
}
int main(int argc,const char*argv[]
{
lua_State*L=luaL_newstate();
luaL_openlibs(L);
lua_sethook(L,hook,lua_MASKCOUNT,100);
//无限递归到pcall
luaL_dostring(L,“函数测试()pcall(测试)打印‘递归’结束pcall(测试)”;
卢厄关闭(L);
printf(“完成!”);
返回0;
}

我还没有找到一种方法,可以在不依赖脚本本身的干预的情况下,干净利落地杀死正在执行长时间运行的lua脚本的线程。以下是我过去采取的一些方法:

  • 如果脚本长时间运行,则很可能处于某个循环中。脚本可以在每次迭代中检查某些全局变量的值。通过在脚本外部设置此变量,可以终止线程
  • 您可以使用lua_resume启动线程。然后可以使用yield()退出脚本
  • 您可以提供自己的pcall实现来检查特定类型的错误。然后,脚本可以使用您的pcall版本可以监视的自定义错误类型调用error():

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

  • 您可以使用
    setjmp
    longjump
    ,就像Lua库内部所做的那样。这将使您脱离
    pcall
    ,并且无需不断出错即可正常运行,从而防止脚本试图处理您的伪错误,并且仍然使您无法执行。(不过,我不知道这对线程的作用有多好。)

    #包括
    #包括
    #包括“lua.h”
    #包括“lualib.h”
    #包括“lauxlib.h”
    jmp_buf place ;;
    void hook(lua_State*L,lua_Debug*ar)
    {
    静态整数倒计时=10;
    如果(倒计时>0)
    {
    --倒计时;
    printf(“倒计时:%d!\n”,倒计时);
    }
    其他的
    {
    longjmp(地点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,“函数测试()pcall(测试)打印‘递归’结束pcall(测试)”;
    卢厄关闭(L);
    printf(“完成!”);
    返回0;
    }
    
    可能没用,但在我使用的lua(luaplayer或PGELua)中,我退出时

    os.exit() 
    

    会话:destroy()


    在您想要销毁lua脚本的地方使用这一单行代码。

    您可能需要查看 项目它的lua抢占式调度程序。 它在钩子中使用lua_yeild函数。因此,您可以挂起lua线程。它也在内部使用longjmp,但它更安全。

    lua\u KFunction cont(lua\u State*L);
    
    lua_KFunction cont(lua_State* L);
    int my_yield_with_res(lua_State* L, int res) {
        cout << " my_yield_with_res \n" << endl;
        return lua_yieldk(L, 0, lua_yield(L, res), cont(L));/* int lua_yieldk(lua_State * L, int res, lua_KContext ctx, lua_KFunction k);
        Приостанавливает выполнение сопрограммы(поток). Когда функция C вызывает lua_yieldk, работающая
        сопрограмма приостанавливает свое выполнение и вызывает lua_resume, которая начинает возврат данной сопрограммы.
        Параметр res - это число значений из стека, которые будут переданы в качестве результатов в lua_resume.
        Когда сопрограмма снова возобновит выполнение, Lua вызовет заданную функцию продолжения k для продолжения выполнения
        приостановленной C функции(смотрите §4.7). */
    };
    int hookFunc(lua_State* L, lua_Debug* ar) {
        cout << " hookFunc \n" << endl;
        return my_yield_with_res(L, 0);// хук./
    };
    
    lua_KFunction cont(lua_State* L) {// функция продолжения.
        cout << " hooh off \n" << endl;
        lua_sethook(L, (lua_Hook)hookFunc, LUA_MASKCOUNT, 0);// отключить хук foo.
        return 0;
    };
    
    struct Func_resume {
        Func_resume(lua_State* L, const char* funcrun, unsigned int Args) : m_L(L), m_funcrun(funcrun), m_Args(Args) {}
        //имена функций, кол-во агрументов.
    private:
        void func_block(lua_State* L, const char* functionName, unsigned int Count, unsigned int m_Args) {
            lua_sethook(m_L, (lua_Hook)hookFunc, LUA_MASKCOUNT, Count); //вызов функции с заданной паузой.
            if (m_Args == 0) {
                lua_getglobal(L, functionName);// получить имя функции.
                lua_resume(L, L, m_Args);
            }
            if (m_Args != 0) {
                int size = m_Args + 1;
                lua_getglobal(L, functionName);
                for (int i = 1; i < size; i++) {
                    lua_pushvalue(L, i);
                }
                lua_resume(L, L, m_Args);
            }
        };
    public:
        void Update(float dt) {
            unsigned int Count = dt * 100.0;// Время работы потока.
            func_block(m_L, m_funcrun, Count, m_Args);
        };
        ~Func_resume() {}
    private:
        lua_State* m_L;
        const char* m_funcrun; // имя функции.
        unsigned int m_Count;// число итерации.
        unsigned int m_Args;
    };
    
    const char* LUA = R"(
    function main(y) 
      --print(" func main arg, a = ".. a.." y = ".. y)      
    for i = 1, y do
      print(" func main count = ".. i)      
      end
    end
    )";
    int main(int argc, char* argv[]) {
        lua_State* L = luaL_newstate();/*Функция создает новое Lua состояние. */
        luaL_openlibs(L);
        luaL_dostring(L, LUA);
        //..pushlua(L, 12);
        pushlua(L, 32);
        //do {
            Func_resume func_resume(L, "main", 2);
            func_resume.Update(1.7);
            lua_close(L);
    //  } while (LUA_OK != lua_status(L)); // Пока  поток не завершен.
    
    
        return 0;
    };
    
    int my_yield_与_res(lua_State*L,int res){
    除非脚本退出,否则我无法正常退出线程。特别是,我需要线程在
    lua\u pcall
    返回后释放其堆栈。请参阅为什么我不能直接终止线程。我想为用户的脚本提供
    pcall
    函数,以便他们可以在内部使用异常。是否有解决方法round?可能是不可修补的错误?@deft_code:如果使用
    pcall
    ,Lua中没有不可修补的错误。但是,您可以重新定义
    pcall
    ,以捕获用于退出脚本并传递其他内容的特定错误值。@lhf:这是一个非常好的建议,可以重新定义pcall()!如果在我尝试放弃时,用户的脚本处于协同程序中会怎样?我认为在这种情况下,用户协同程序将返回而不是全局脚本。我认为我缺少的部分是,一旦我决定脚本需要终止,钩子函数将不断返回错误。实际上,我认为有更好的解决方案。我将以不同的方式发布它这是我使用的解决方案。我仍然有点担心Lua可能泄漏了一些东西,但它是g
    lua_KFunction cont(lua_State* L);
    int my_yield_with_res(lua_State* L, int res) {
        cout << " my_yield_with_res \n" << endl;
        return lua_yieldk(L, 0, lua_yield(L, res), cont(L));/* int lua_yieldk(lua_State * L, int res, lua_KContext ctx, lua_KFunction k);
        Приостанавливает выполнение сопрограммы(поток). Когда функция C вызывает lua_yieldk, работающая
        сопрограмма приостанавливает свое выполнение и вызывает lua_resume, которая начинает возврат данной сопрограммы.
        Параметр res - это число значений из стека, которые будут переданы в качестве результатов в lua_resume.
        Когда сопрограмма снова возобновит выполнение, Lua вызовет заданную функцию продолжения k для продолжения выполнения
        приостановленной C функции(смотрите §4.7). */
    };
    int hookFunc(lua_State* L, lua_Debug* ar) {
        cout << " hookFunc \n" << endl;
        return my_yield_with_res(L, 0);// хук./
    };
    
    lua_KFunction cont(lua_State* L) {// функция продолжения.
        cout << " hooh off \n" << endl;
        lua_sethook(L, (lua_Hook)hookFunc, LUA_MASKCOUNT, 0);// отключить хук foo.
        return 0;
    };
    
    struct Func_resume {
        Func_resume(lua_State* L, const char* funcrun, unsigned int Args) : m_L(L), m_funcrun(funcrun), m_Args(Args) {}
        //имена функций, кол-во агрументов.
    private:
        void func_block(lua_State* L, const char* functionName, unsigned int Count, unsigned int m_Args) {
            lua_sethook(m_L, (lua_Hook)hookFunc, LUA_MASKCOUNT, Count); //вызов функции с заданной паузой.
            if (m_Args == 0) {
                lua_getglobal(L, functionName);// получить имя функции.
                lua_resume(L, L, m_Args);
            }
            if (m_Args != 0) {
                int size = m_Args + 1;
                lua_getglobal(L, functionName);
                for (int i = 1; i < size; i++) {
                    lua_pushvalue(L, i);
                }
                lua_resume(L, L, m_Args);
            }
        };
    public:
        void Update(float dt) {
            unsigned int Count = dt * 100.0;// Время работы потока.
            func_block(m_L, m_funcrun, Count, m_Args);
        };
        ~Func_resume() {}
    private:
        lua_State* m_L;
        const char* m_funcrun; // имя функции.
        unsigned int m_Count;// число итерации.
        unsigned int m_Args;
    };
    
    const char* LUA = R"(
    function main(y) 
      --print(" func main arg, a = ".. a.." y = ".. y)      
    for i = 1, y do
      print(" func main count = ".. i)      
      end
    end
    )";
    int main(int argc, char* argv[]) {
        lua_State* L = luaL_newstate();/*Функция создает новое Lua состояние. */
        luaL_openlibs(L);
        luaL_dostring(L, LUA);
        //..pushlua(L, 12);
        pushlua(L, 32);
        //do {
            Func_resume func_resume(L, "main", 2);
            func_resume.Update(1.7);
            lua_close(L);
    //  } while (LUA_OK != lua_status(L)); // Пока  поток не завершен.
    
    
        return 0;
    };