<转> 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  阅读(359)  评论(0编辑  收藏  举报

导航