<转> Lua使用心得(2)
在lua脚本调用中,如果我们碰到一种不好的脚本,例如:
while 1 do do end
那我们的程序主线程也会被阻塞住。那我们如何防止这种问题呢?下面就给出一个解决的办法。
首先为了不阻塞主线程,那我们就要开一个线程,把处理脚本的操作都放在这个新开的工作线程里。(要详细了解工作线程和界面线程的区别和管理,请参看大神的一篇文章BLOG下Windows编程里的《Windows 线程漫谈——界面线程和工作者线程》)。
总体思路:
1、开线程来执行脚本解析,下面是StartRun()
2、导出一个判断是否结束函数,让脚本每个循环都调用,判断线程是否该结束了,这个函数在下面是IsThreadExit(),返回一个字符串("exit" 表示while循环该结束了,"Notexit" 表示线程还不能结束)
3、如果主线程需要主动结束线程,就调用StopRun()
4、最好导出一个 ySleep 停顿函数,以免while循环里执行太快,导致CPU被高占用。
按照这种思路,lua脚本变成如下形式:
1 while 1 do 2 3 4 exitThread=IsThreadExit(); 5 ySleep(100); 6 7 if exitThread == "exit" then 8 break; 9 end; 10 11 end; 12 13
VC代码如下,其中的Output是一个输出函数,你可以用MessageBox来代替:
// 全局变量
// 标志线程是否要结束
BOOL g_bExitDofile = FALSE;
// 线程句柄
HANDLE g_hDofile = NULL;
// 需要导出的函数
// 让 Lua 判断循环是否可以退出
1 static int IsThreadExit(lua_State* L) 2 { 3 if(g_bExitDofile) 4 lua_pushlstring(L, "exit", 4); 5 else 6 lua_pushlstring(L, "Notexit", 7); 7 8 // 一个返回值 9 return 1; 10 } 11 12
// 停顿函数
1 int ySleep(lua_State* L) 2 { 3 int d = luaL_checkinteger(L, 1); 4 Sleep(d); 5 6 return 0; 7 }
// 注册以上函数
1 int RegFunc() 2 3 { 4 lua_pushcfunction(g_pLua, IsThreadExit); 5 lua_setglobal(g_pLua, "IsThreadExit"); 6 7 lua_pushcfunction(g_pLua, ySleep); 8 lua_setglobal(g_pLua, "ySleep"); 9 10 11 12 return 0; 13 14 }
// 线程函数
1 DWORD WINAPI DofileThread(LPVOID lpParam) 2 { 3 LPCTSTR strFilePath = (LPCTSTR)lpParam; 4 luaL_dofile(g_pLua, strFilePath); 5 6 StackDump(g_pLua); 7 8 return 0; 9 }
1 // 线程启动 2 3 int StartRun(LPCTSTR strFilePath) 4 { 5 6 // 注册所有需要导出的函数 7 RegFunc(); 8 9 if(g_hDofile == NULL) 10 { 11 // 创建线程来执行LUA脚本 12 g_hDofile = CreateThread(NULL, 0, DofileThread, (LPVOID)strFilePath, 0, NULL); 13 } 14 else 15 { 16 Output("请先调用StopRun()"); 17 } 18 19 return 0; 20 } 21 22 23 24 // 停止线程 25 26 int StopRun() 27 { 28 // 如果线程正在跑 29 if(g_hDofile) 30 { 31 // 给lua循环结束的信号 32 g_bExitDofile = TRUE; 33 // 等待线程退出 34 DWORD dwRet = WaitForSingleObject(g_hDofile, INFINITE); 35 36 // 如果顺利退出 37 if(dwRet == WAIT_OBJECT_0) 38 { 39 CloseHandle(g_hDofile); 40 g_hDofile = NULL; 41 g_bExitDofile = FALSE; 42 43 Output("Dofile thread exited!"); 44 } 45 // 否则强硬杀掉线程 46 else 47 { 48 DWORD dwExitCode; 49 GetExitCodeThread(g_hDofile, &dwExitCode); 50 51 TerminateThread(g_hDofile, dwExitCode); 52 53 g_hDofile = NULL; 54 g_bExitDofile = FALSE; 55 56 Output("Dofile thread was killed!"); 57 } 58 } 59 60 return 0; 61 }
上面这个方法是利用了线程的本身特性解决掉脚本阻塞的问题。还可以使用LUA本身的HOOKS机制来防止脚本的阻塞,这个方法下次再说了。。。
posted on 2016-03-16 10:00 Sam.Richard 阅读(361) 评论(0) 编辑 收藏 举报