在lua指令碼調用中,如果我們碰到一種不好的指令碼,例如:
while 1 do
do
end
那我們的程式主線程也會被阻塞住。那我們如何防止這種問題呢?下面就給出一個解決的辦法。
首先為了不阻塞主線程,那我們就要開一個線程,把處理指令碼的操作都放在這個新開的背景工作執行緒裡。(要詳細瞭解背景工作執行緒和介面線程的區別和管理,請參看本人的另一篇文章BLOG下Windows編程裡的《Windows 線程漫談——介面線程和工作者線程》)。
總體思路:
1、開線程來執行指令碼解析,下面是StartRun()
2、匯出一個判斷是否結束函數,讓指令碼每個迴圈都調用,判斷線程是否該結束了,這個函數在下面是IsThreadExit(),返回一個字串("exit" 表示while迴圈該結束了,"Notexit" 表示線程還不能結束)
3、如果主線程需要主動結束線程,就調用StopRun()
4、最好匯出一個 ySleep 停頓函數,以免while迴圈裡執行太快,導致CPU被高佔用。
按照這種思路,lua指令碼變成如下形式:
while 1 do
exitThread=IsThreadExit();
ySleep(100);
if exitThread == "exit" then
break;
end;
end;
VC代碼如下,其中的Output是一個輸出函數,你可以用MessageBox來代替:
// 全域變數
// 標誌線程是否要結束
BOOL g_bExitDofile = FALSE;
// 線程控制代碼
HANDLE g_hDofile = NULL;
// 需要匯出的函數
// 讓 Lua 判斷迴圈是否可以退出
static int IsThreadExit(lua_State* L)
{
if(g_bExitDofile)
lua_pushlstring(L, "exit", 4);
else
lua_pushlstring(L, "Notexit", 7);
// 一個傳回值
return 1;
}
// 停頓函數
int ySleep(lua_State* L)
{
int d = luaL_checkinteger(L, 1);
Sleep(d);
return 0;
}
// 註冊以上函數
int RegFunc()
{
lua_pushcfunction(g_pLua, IsThreadExit);
lua_setglobal(g_pLua, "IsThreadExit");
lua_pushcfunction(g_pLua, ySleep);
lua_setglobal(g_pLua, "ySleep");
return 0;
}
// 線程函數
DWORD WINAPI DofileThread(LPVOID lpParam)
{
LPCTSTR strFilePath = (LPCTSTR)lpParam;
luaL_dofile(g_pLua, strFilePath);
StackDump(g_pLua);
return 0;
}
// 線程啟動
int StartRun(LPCTSTR strFilePath)
{
// 註冊所有需要匯出的函數
RegFunc();
if(g_hDofile == NULL)
{
// 建立線程來執行LUA指令碼
g_hDofile = CreateThread(NULL, 0, DofileThread, (LPVOID)strFilePath, 0, NULL);
}
else
{
Output("請先調用StopRun()");
}
return 0;
}
// 停止線程
int StopRun()
{
// 如果線程正在跑
if(g_hDofile)
{
// 給lua迴圈結束的訊號
g_bExitDofile = TRUE;
// 等待線程退出
DWORD dwRet = WaitForSingleObject(g_hDofile, INFINITE);
// 如果順利退出
if(dwRet == WAIT_OBJECT_0)
{
CloseHandle(g_hDofile);
g_hDofile = NULL;
g_bExitDofile = FALSE;
Output("Dofile thread exited!");
}
// 否則強硬殺掉線程
else
{
DWORD dwExitCode;
GetExitCodeThread(g_hDofile, &dwExitCode);
TerminateThread(g_hDofile, dwExitCode);
g_hDofile = NULL;
g_bExitDofile = FALSE;
Output("Dofile thread was killed!");
}
}
return 0;
}
上面這個方法是利用了線程的本身特性解決掉指令碼阻塞的問題。還可以使用LUA本身的HOOKS機制來防止指令碼的阻塞,這個方法下次再說了。。。