2

C関数がlua関数を呼び出し、lua関数がC APIを呼び出す場合、luaがC APIを呼び出すと機能し、longjmpエラー

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;
}

ルアコード

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

1 に答える 1

5

lua_newthreadではなく、によって返されたスレッドで lua_resume を呼び出しますlua_newstate

lua_resumeしたがって、コードでは、最初のものを次のように変更する必要がありますlua_(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_pcallk継続lua_yieldk関数を引数として受け取る必要があります。あなたの場合は 0 です。実際にlua_yieldkは、継続関数として 0 を使用できますが、制御は、C 関数の呼び出しが行われた Lua スクリプトに戻されます。
  • 次に、これらの関数への呼び出しは、メイン スレッドではなく、コルーチン スレッド内で行う必要があります。
  • そして最後に、C 呼び出しの境界を越えて譲歩することはできません。つまり、呼び出しlua_pcallkて、pcallk が呼び出しているチャンクが生成されると、継続関数が実行されます。lua_pcallkただし、 (この例では) を生成する C 関数を呼び出す Lua 関数を呼び出すことはできません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;
}

ルアコード:

local pcallktest = ...
pcallktest()

このコードは、ファイル「Test.lua」から新しいコルーチンを開始します。Lua コードは C functionpcallktestを呼び出し、それはlua_pcallk別の Lua 関数を呼び出します。contyield が発生すると、実行は への引数として提供された関数にジャンプ (longjmp) しlua_pcallkます。関数がcont戻ると、コルーチンの実行が終了lua_resumeし、_tmain戻ります。

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;
}

ルアコード:

local yieldktest = ...
yieldktest()

このビットは、C 関数内から発生するコルーチンを実行します ( yieldktest)。その後、コルーチンが再開されると (2 回目lua_resume)、制御が継続関数に戻され、継続contとして実行されyieldktestます。

これらの例はlua_getctx、状態を処理したりスタックしたりするのではなく、それらの機能のメカニズムを示すだけです。

于 2013-05-07T14:25:59.783 に答える