Tencent / xLua

xLua is a lua programming solution for C# ( Unity, .Net, Mono) , it supports android, ios, windows, linux, osx, etc.
Other
9.41k stars 2.45k forks source link

xlua DoString时候死循环 C#端如何处理 #1077

Closed Tunied closed 1 year ago

Tunied commented 1 year ago

我使用xlua作为游戏的内嵌脚本语言. 允许玩家自定义脚本.

现在有个玩家在脚本里面写了一个死循环. 当我用DoString去加载这个脚本时候会直接卡死.

于是我在外面加入了一个Task

var isSucceed = false;
var task = Task.Run(() => { 
    isSucceed = sandbox.DoString(xxxx)//这里简化一下.核心就是加载这个脚本执行DoString
});

bool isCompletedSuccessfully = task.Wait(TimeSpan.FromMilliseconds(1500)); //1.5s timeout

if (!isCompletedSuccessfully)
{
    CELog.LogError("加载脚本超时");
    isSucceed = false;

    luaEnv.Dispose(); //Kill掉当前的Evn

    return; //不再加载后续脚本
}

现在是只要调用 luaEnv.Dispose() 编辑器就直接闪退. 无论是这里Timeout了调用.还是等几秒以后.

我感觉是因为 Task的Timeout只是在超时后回调. 但是此时 lua还在死锁中. 所以我无法Dipose

官方的FAQ有提了一句

调用LuaEnv.Dispose崩溃 很可能是这个Dispose操作是由lua那驱动执行,相当于在lua执行的过程中把lua虚拟机给释放了,改为只由C#执行即可。

我感觉和我这个情况是一样的.

所以这种情况我应该怎么处理?

谢谢

chexiongsheng commented 1 year ago

虚拟机运行中去Dispose必崩溃。 只有一个办法,先把虚拟机停下来再Dispose

Tunied commented 1 year ago

抱歉. 我还想问一下.

https://ld246.com/article/1522147783147

这篇文章里面给了一个思路 就是 设置一个TimeoutHook. 然后如果检测到超时以后 通过luaL_error抛出一个异常来终止当前的执行.

我在 NLua 里面找到了Hook方法

https://github.com/NLua/NLua/issues/56

lua.SetDebugHook(NLua.Event.EventMasks.LUA_MASKLINE, 0);

请问 在xlua里面怎么设置类似的 DebugHook, 然后就是我在Hook里面检测到超时 用哪个方法可以手动抛出异常 终止当前的执行呢.

谢谢

Tunied commented 1 year ago

大佬 我刚试了一下

因为我外部是单独起了用一个Task监听的Timeout. 所以我就直接在 Timeout了以后

 public void Kill() { LuaAPI.xlua_csharp_str_error(L, "Kill"); }

直接在 LuaEnv.cs 里面加了一个Kill方法. 然后调用的Kill. 目前问题解决了.

我想问下. 这么做的话会有什么隐患么.

谢谢.

chexiongsheng commented 1 year ago

抱歉. 我还想问一下.

https://ld246.com/article/1522147783147

这篇文章里面给了一个思路 就是 设置一个TimeoutHook. 然后如果检测到超时以后 通过luaL_error抛出一个异常来终止当前的执行.

我在 NLua 里面找到了Hook方法

NLua/NLua#56

lua.SetDebugHook(NLua.Event.EventMasks.LUA_MASKLINE, 0);

请问 在xlua里面怎么设置类似的 DebugHook, 然后就是我在Hook里面检测到超时 用哪个方法可以手动抛出异常 终止当前的执行呢.

谢谢

这个思路ok,lua_sethook 自己导出一下就有了。怎么导出查下C# pinvoke的文档

Tunied commented 1 year ago

我现在 直接在LuaEnv.cs里面加了一个方法. C#端直接用Task的Timetout监听的. 试了一下.没有闪退

public void Kill() { LuaAPI.xlua_csharp_str_error(L, "Kill"); }

因为我C#调用Lua的情况比较简单. Lua端的逻辑也比较弱. 这个Task监听方式完全满足我的需求了.

我想问下我这么调用LuaAPI.xlua_csharp_str_error有啥隐患么.

底层不太懂 :sweat_smile:

感谢.

chexiongsheng commented 1 year ago

我现在 直接在LuaEnv.cs里面加了一个方法. C#端直接用Task的Timetout监听的. 试了一下.没有闪退

public void Kill() { LuaAPI.xlua_csharp_str_error(L, "Kill"); }

因为我C#调用Lua的情况比较简单. Lua端的逻辑也比较弱. 这个Task监听方式完全满足我的需求了.

我想问下我这么调用LuaAPI.xlua_csharp_str_error有啥隐患么.

底层不太懂 😅

感谢.

这种感觉有导致虚拟机错乱的风险。

Tunied commented 1 year ago

感谢大佬.

我刚才又测了测 目前我用这个方法没啥问题. 可能我Lua和C#之间调用比较简单吧.

我就先这么用着了:smiley:

JosephStar318 commented 8 months ago

I've now added a method directly to it. The C# side listens directly with Task's Timetout. Gave it a try. There was no flashbackLuaEnv.cs

public void Kill() { LuaAPI.xlua_csharp_str_error(L, "Kill"); }

Because I'm C# calling Lua is relatively simple. The logic on the Lua side is also weak. This task listening method fully meets my needs. I'd like to ask if there's any hidden danger in calling me like this.LuaAPI.xlua_csharp_str_error I don't understand 😅 the bottom layer Thank.

This feeling runs the risk of causing the virtual machine to become deranged.

I think it has for me... unity crashed when i called Kill()