2013-05-07 97 views
1

它的工作原理,如果一個C函數調用Lua函數當Lua調用C API 和LUA函數調用C API,longjmp的錯誤如何獲得LUA腳本C功能

lua_yieldk,lua_callk和lua_pcallk 如何它工作嗎?

我的C代碼:

int trace(lua_State *L) 
{ 
    const char *str = luaL_checkstring(L, 1); 
    printf("%d:%s\n", GetTickCount(), str); 
    return 1; 
} 

int pause(lua_State *L) 
{ 
    printf("pause"); 
    return lua_yield(L, 0); 
} 

int _tmain(int argc, _TCHAR* argv[]) 
{ 
    lua_State *L = luaL_newstate(); 
    luaL_openlibs(L); 
    lua_pushcfunction(L, pause); 
    lua_setglobal(L, "pause"); 
    lua_pushcfunction(L, trace); 
    lua_setglobal(L, "trace"); 
    if (luaL_loadfile(L, "test.lua")) 
     error(L, "cannot run script %s\n", lua_tostring(L,-1)); 
    lua_resume(L, NULL, 0); 
     lua_getglobal(L, "t"); 
    lua_pcallk(L, 0, 0, 0, 0, 0); 
    lua_resume(L, NULL, 0); 
    lua_resume(L, NULL, 0); 
    lua_resume(L, NULL, 0); 
    lua_resume(L, NULL, 0); 
    lua_close(L); 
    getchar(); 
    return 0; 
} 

Lua代碼

function t() 
pause(2) 
pause(2) 
pause(2) 
pause(2) 
end 

回答

5

你叫由lua_newthread,不lua_newstate返回線程lua_resume。

因此,在你的代碼,你要麼必須改變第一lua_resumelua_(p)call

if (luaL_loadfile(L, "test.lua")) 
    error(L, "cannot run script %s\n", lua_tostring(L,-1)); 
lua_pcall(L, 0, 0, 0); 

或交換luaL_loadfileluaL_dofile

if (luaL_dofile(L, "test.lua")) 
    error(L, "cannot run script %s\n", lua_tostring(L,-1)); 
//lua_resume(L, NULL, 0); Not necessary anymore 

我沒有與設置的效率全球t這裏。

我們問題的主要觀點:

  • 首先,每次調用lua_callklua_pcallklua_yieldk需要接收的延續函數作爲參數。在你的情況下它是0.實際上,lua_yieldk可以取0作爲延續函數,但是然後控制被傳回到Lua腳本,在那裏調用了C函數。
  • 接下來,對這些函數的任何調用都必須在協程線程中進行,而不是主線程。
  • 最後,你不能通過C調用邊界。也就是說,當你調用lua_pcallk和pcallk正在調用yield的塊時,繼續功能被執行。但是,您不能讓lua_pcallk調用一個Lua函數,該函數又調用一個產生的C函數(在您的示例中爲pause)。這是被禁止的。

lua_pcallk一個例子:

int cont(lua_State *L) 
{ 
    getchar(); 
    return 0; 
} 

int pcallktest(lua_State *L) 
{ 
    luaL_loadstring(L, "yield()"); 
    int test = lua_pcallk(L, 0, 0, 0, 0, cont); 
    return 0; 
} 
int _tmain(int argc, _TCHAR* argv[]) 
{ 
    lua_State *L = luaL_newstate(); 
    luaL_openlibs(L); 
    lua_State *T = lua_newthread(L); 

    luaL_loadfile(T, "Test.lua"); 
    lua_pushcfunction(T, pcallktest); 
    lua_resume(T, NULL, 1); 
    return 0; 
} 

Lua代碼:

local pcallktest = ... 
pcallktest() 

現在這段代碼來自文件 「Test.lua」 開始一個新的協程。 Lua代碼調用C函數pcallktest,後者又調用另一個Lua函數lua_pcallk,該函數剛剛生成。當收益發生時,執行跳轉(longjmp)到cont函數,該函數作爲lua_pcallk的參數提供。當cont函數返回時,協程執行結束並從_tmain返回lua_resume

lua_yieldk一個例子:

int cont(lua_State *L) 
{ 
    getchar(); 
    return 0; 
} 

int yieldktest(lua_State *L) 
{ 
    return lua_yieldk(L, 0, 0, cont); 
} 
int _tmain(int argc, _TCHAR* argv[]) 
{ 
    lua_State *L = luaL_newstate(); 
    luaL_openlibs(L); 
    lua_State *T = lua_newthread(L); 

    luaL_loadfile(T, "Test.lua"); 
    lua_pushcfunction(T, yieldktest); 
    lua_resume(T, NULL, 1); 
    lua_resume(T, NULL, 0); 
    return 0; 
} 

Lua代碼:

local yieldktest = ... 
yieldktest() 

該位依次執行協程從C函數(yieldktest)內的產率。然後當協程被恢復(第二個lua_resume)時,控制權返回到繼續功能cont,該功能作爲yieldktest的繼續執行。

這些示例不涉及lua_getctx和堆棧狀態,但僅僅演示了這些函數的機制。

+0

非常感謝你....我現在可以睡了^^ – user1790687 2013-05-08 05:25:18