2013-05-20 14 views
8

私はluaを使用しています。私はpcallが保護された呼び出しであることを知っていて、私の質問は両方とも同じCコードになります。例えば通常の関数呼び出しとpcallの違いは何ですか

function a(arg) 
    ... 
end 

通常の呼び出し:

a(arg) 

保護されたコール:

pcall(a, arg) 

は実際に私が破損からlua_Stateを保護するために 'lua_lock/lua_unlock' を使用しています。そして、lua_pcallがlua_lock/lua_unlockを呼び出しているのを見ることができますが、関数呼び出しの通常の方法も 'lua_pcall'に基づいているか 'lua_lock/lua_unlock'を使用しているかどうかわかりません。そうでなければ、 'pcall(...)'を呼び出すすべての関数を 'lua_lock/lua_unlock'の恩恵を得るために変更しなければならないのでしょうか?

誰かが説明できますか?ありがとうございました

答えて

15

pcallは、luaのエラーを処理するために使用されています。私はそれを使用する方法を示すために、次の例を作りました:

まず、我々は今、私たちの最初の例として、我々は次のように定義し、私

function makeError(n) 
    return 'N'+n; 
end 

エラーが生成されます知っている機能を作ります

function pcallExample1() 
    if pcall(makeError,n) then 
     print("no error!") 
    else 
     print("That method is broken, fix it!") 
    end 
end 

は、我々は呼び出すpcallExample1

表示までunhandedたままエラーを持つことになり、これを呼び出す

function pcallExample2() 
    if makeError(5) then 
     print("no error!") 
    else 
     print("That method is broken, fix it!") 
    end 
end 

とバブル:

Lua 5.1.3 Copyright (C) 1994-2008 Lua.org, PUC-Rio 
That method is broken, fix it! 

は反対のことを実証するために:210

と出力を得る

lua: /Users/henryhollinworth/Desktop/s.lua:2: attempt to perform arithmetic on a string value 

Cは、PCALLは

lua_pcallkの両方が lua_lock()lua_unlock()の使用を行うことを注意 lua_callk

LUA_API void lua_callk (lua_State *L, int nargs, int nresults, int ctx, 
         lua_CFunction k) { 
    StkId func; 
    lua_lock(L); 
    api_check(L, k == NULL || !isLua(L->ci), 
    "cannot use continuations inside hooks"); 
    api_checknelems(L, nargs+1); 
    api_check(L, L->status == LUA_OK, "cannot do calls on non-normal thread"); 
    checkresults(L, nargs, nresults); 
    func = L->top - (nargs+1); 
    if (k != NULL && L->nny == 0) { /* need to prepare continuation? */ 
    L->ci->u.c.k = k; /* save continuation */ 
    L->ci->u.c.ctx = ctx; /* save context */ 
    luaD_call(L, func, nresults, 1); /* do the call */ 
    } 
    else /* no continuation or no yieldable */ 
    luaD_call(L, func, nresults, 0); /* just do the call */ 
    adjustresults(L, nresults); 
    lua_unlock(L); 
} 

に対し

LUA_API int lua_pcallk (lua_State *L, int nargs, int nresults, int errfunc, 
         int ctx, lua_CFunction k) { 
    struct CallS c; 
    int status; 
    ptrdiff_t func; 
    lua_lock(L); 
    api_check(L, k == NULL || !isLua(L->ci), 
    "cannot use continuations inside hooks"); 
    api_checknelems(L, nargs+1); 
    api_check(L, L->status == LUA_OK, "cannot do calls on non-normal thread"); 
    checkresults(L, nargs, nresults); 
    if (errfunc == 0) 
    func = 0; 
    else { 
    StkId o = index2addr(L, errfunc); 
    api_checkvalidindex(L, o); 
    func = savestack(L, o); 
    } 
    c.func = L->top - (nargs+1); /* function to be called */ 
    if (k == NULL || L->nny > 0) { /* no continuation or no yieldable? */ 
    c.nresults = nresults; /* do a 'conventional' protected call */ 
    status = luaD_pcall(L, f_call, &c, savestack(L, c.func), func); 
    } 
    else { /* prepare continuation (call is already protected by 'resume') */ 
    CallInfo *ci = L->ci; 
    ci->u.c.k = k; /* save continuation */ 
    ci->u.c.ctx = ctx; /* save context */ 
    /* save information for error recovery */ 
    ci->u.c.extra = savestack(L, c.func); 
    ci->u.c.old_allowhook = L->allowhook; 
    ci->u.c.old_errfunc = L->errfunc; 
    L->errfunc = func; 
    /* mark that function may do error recovery */ 
    ci->callstatus |= CIST_YPCALL; 
    luaD_call(L, c.func, nresults, 1); /* do the call */ 
    ci->callstatus &= ~CIST_YPCALL; 
    L->errfunc = ci->u.c.old_errfunc; 
    status = LUA_OK; /* if it is here, there were no errors */ 
    } 
    adjustresults(L, nresults); 
    lua_unlock(L); 
    return status; 
} 

ある

static int luaB_pcall (lua_State *L) { 
    int status; 
    luaL_checkany(L, 1); 
    lua_pushnil(L); 
    lua_insert(L, 1); /* create space for status result */ 
    status = lua_pcallk(L, lua_gettop(L) - 2, LUA_MULTRET, 0, 0, pcallcont); 
    return finishpcall(L, (status == LUA_OK)); 
} 

として定義されます。両方ともlua_Stateをロックまたはロック解除します。

+0

通常、特に開発時には、 'xpcall'を使用する方が望ましいです。なぜなら、実際にはエラーメッセージが出て、それがトレースバックされ、エラーが発生してもLuaランタイムに影響しないからです。 – dualed

関連する問題