2013-05-20 14 views
8

Sto usando lua e so che pcall è per le chiamate protette e la mia domanda è se entrambi i modi di chiamare tutti arrivino allo stesso codice C. per esempio.Qual è la differenza dietro la normale chiamata di funzione e pcall

function a(arg) 
    ... 
end 

chiamata normale:

a(arg) 

chiamata protetto:

pcall(a, arg) 

In realtà sto usando 'lua_lock/lua_unlock' per proteggere l'lua_State dalla corruzione. E forma la fonte (lua 5.1.4) Vedo che 'lua_pcall' sta chiamando 'lua_lock/lua_unlock', ma non sono sicuro che il normale modo di chiamare funzioni sia basato su 'lua_pcall' o che usi 'lua_lock/lua_unlock'? Se no, vuol dire che devo cambiare tutta la funzione che chiama a 'pcall (...)' per trarre beneficio da 'lua_lock/lua_unlock'?

Qualcuno potrebbe spiegare? Grazie

risposta

15

pcall viene utilizzato per gestire gli errori in lua. Ho fatto il seguente esempio per dimostrare come usarlo:

Prima facciamo una funzione che mi sapere produrrà un errore

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

Ora, come primo esempio definiamo la seguente

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

invochiamo pcallExample1

pcallExample1() 

E ottenere l'output:

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

Per dimostrare il contrario:

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

Invocare questo avrà l'errore rimangono unhanded e bolla fino al display:

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

In termini di C, PCALL è definito come

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

Dove lua_pcallk è

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

In contrasto 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); 
} 

noti che entrambi fanno uso di lua_lock() e lua_unlock(). Entrambi bloccano e sbloccano lo lua_State.

+0

Si noti che in genere, soprattutto per lo sviluppo, è preferibile utilizzare 'xpcall' poiché è possibile ottenere un messaggio di errore e il traceback da esso mentre non influisce sul runtime Lua in caso di errore. – dualed

Problemi correlati