普通函数调用和pcall背后的区别是什么

时间:2013-05-20 03:21:58

标签: lua

我正在使用lua,我知道pcall用于受保护的调用,我的问题是,如果两种方式都调用同一个C代码。 e.g。

function a(arg)
   ...
end

正常通话:

a(arg)

受保护的电话:

pcall(a, arg)

实际上我正在使用'lua_lock / lua_unlock'来保护lua_State免受破坏。并形成源(lua 5.1.4)我可以看到'lua_pcall'正在调用'lua_lock / lua_unlock',但我不确定函数调用的正常方式是否也基于'lua_pcall'或使用'lua_lock / lua_unlock'?如果没有,这是否意味着我必须将所有调用'pcall(...)'的函数更改为从'lua_lock / lua_unlock'中获益?

有人可以解释一下吗?谢谢

1 个答案:

答案 0 :(得分:17)

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

pcallExample1()

获得输出:

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

为了证明相反的结果:

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

调用此方法会使错误保持不变,并冒泡到显示屏:

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

C而言,pcall定义为

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

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_lock()lua_unlock()。锁定和解锁lua_State

相关问题