zoukankan      html  css  js  c++  java
  • <转> 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机制来防止脚本的阻塞,这个方法下次再说了。。。

  • 相关阅读:
    .NET Cache缓存
    异步
    es6常用功能
    vue-router路由懒加载
    vue中nextTick和$nextTick
    动态模板中 swiper 划不动问题
    javaScript正则判断手机号
    Mac终端使用技巧
    alert IOS自带域名
    vue css background路径不对
  • 原文地址:https://www.cnblogs.com/SamRichard/p/5282289.html
Copyright © 2011-2022 走看看