【问题标题】:Lua inner conflicts with C/Delphi functions?Lua 内部与 C/Delphi 函数冲突?
【发布时间】:2013-04-06 20:02:47
【问题描述】:

我为我的项目实现了计时器(对于 lua 5.1,完整的源代码、dll 和测试可在 http://wintarif.narod.ru/products.htm 获得,所以我将跳过有问题的完整源代码)。 Timer 创建对象并实现 CreateTimerQueueTimer。我做了 3 次不同行为的测试: 共享部分测试脚本

require('timer')

-- params same as CreateTimerQueueTimer: DueTime, Period, Flags
-- flag WT_EXECUTEONLYONCE = 8, timer will stops, enabled set to false
local mt = timer(1000, 1000, 0)

local i = 0;
function myOnTimer()
    print('wow!')
    if i < 5 then
        i = i + 1
    else
        print("stopping timer")
        mt:StopTimer()
    end
end

mt:SetEvent('OnTimer', myOnTimer)
mt:StartTimer()

当我使用时

while mt:GetEnabled() do --more buggy way
end

存在“未处理的异常”,但它每秒不间断地打印wow!

while true do --buggy way, stack conflict during callback?
    local enabled = mt:GetEnabled()
    if not(enabled) then
        break
    end
end

5: bad argument #-2 to 'GetEnabled' (attempt to concatenatetimerLOADLIB: a table valuetimerstring)5: bad argument #-2 to 'GetEnabled' (timer expected, got table) 之类的错误,或者它可以工作到来自 dll 的第一个事件并在没有错误的情况下停止。

只有

function WaitForTimer()
    while true do
        local is_enabled = mt:GetEnabled()
        if not(is_enabled) then
            print("not enabled")
            return coroutine.yield()
        end
    end
end

co = coroutine.create(WaitForTimer)
coroutine.resume(co)

正常工作。

GetEnabled() 的 Dll 实现非常简单,静态 cdecl 函数

function StaticThunk(L: Plua_State): integer; cdecl;
var
  o: TLuaWrapper;
begin
  o := TLuaWrapper(lua_topointer(L, lua_upvalueindex(1)));
  result := o.Thunk(L);
end;

提取对象,对象的Thunk

function TLuaWrapper.Thunk(L: Plua_State): integer;
var
  i: integer;
  pobj: PtrT;
begin
  { redirect method call to the real thing }
  i := lua_tointeger(L, lua_upvalueindex(2)); // function's index, index is 2 since 1 is self ptr now
  lua_pushnumber(L, 0);
  lua_gettable(L, 1); // get the class table (i.e, self)

  pobj := PtrT(luaL_checkudata(L, -1, PAnsiChar(REG_NAME)));
  lua_remove(L, -1); // remove the userdata from the stack
  lua_remove(L, 1); // remove object from the stack

  try
    result := ClassApiArray[i].func(L, pobj^); // execute the thunk
  except
      result := 0;
  end;
end;

准确

function TLuaWrapper.GetEnabled(L: Plua_State; obj: TQueuedTimer): integer;
begin
  // lua_settop(L, 0);
  lua_pushboolean(L, obj.Enabled);
  result := 1;
end;

Lua 内部到底发生了什么?为什么我有冲突?

更多信息:在lua.exe 下从LuaForWindows 执行的脚本。

【问题讨论】:

    标签: api lua


    【解决方案1】:

    您传递给CreateTimerQueueTimer() 的回调函数将由Windows 在另一个线程中异步执行
    但是你不能同时在两个不同的线程中使用相同的 Lua 状态。
    因此,当您的主脚本在 Lua 状态下运行时,您不能在 Lua 状态下执行回调函数。
    在多个线程中使用 Lua 状态会导致不可预知的行为和奇怪的错误消息。
    如果您的回调函数变得更复杂,您的带有协同程序的代码目前可以正常工作,但也会出现错误。

    Lua 状态不是线程安全的。
    因此,CreateTimerQueueTimer 的功能不能绑定到 Lua。 Пичалька :-(

    【讨论】:

    • 当我使用的不是来自LuaForWindows 的 Lua.exe 而是 Lua 环境(使用 Lua51.dll 的应用程序)时,甚至在第一次回调发生之前(DueTime 1000 毫秒)和(我的研究)就发生了 2 个错误脚本中的错误在 Delphi(FastMM4 内存管理器)下制作完全没有错误。问题是关于 Lua 做了什么:为堆栈分配内存,将数据放入堆栈,调用函数,函数从堆栈和表中提取数据并通过同一堆栈返回数据,Lua 垃圾收集局部变量?正确的?为什么会出现错误?
    • @user2091150 - 你的测试用例非常大。请编写一个小程序(Delphi+Lua)显示您的错误并且不使用回调函数。
    • 问题是:我对Hello Worlds没有问题:)
    • @user2091150 - 暴雪可能会强制在主线程中运行所有回调函数(如 Delphi 中的 synchronize 强制在 VCL 线程中执行您的过程)。你有关于在暴雪的 Lua 环境中处理事件的描述的链接吗?
    • @user2091150 - 你不能在 Lua 中创建公平的回调函数,但可以在 Delphi 中实现 wait_any_event(array_of_events) 函数并使其可用于你的 Lua 代码。
    猜你喜欢
    • 2020-12-27
    • 1970-01-01
    • 2010-12-14
    • 1970-01-01
    • 1970-01-01
    • 2012-07-10
    • 1970-01-01
    • 2018-01-13
    • 1970-01-01
    相关资源
    最近更新 更多