Error handling lua协程的堆栈是隐式输入的,而不需要调用resume?

Error handling lua协程的堆栈是隐式输入的,而不需要调用resume?,error-handling,lua,callstack,implicit,coroutine,Error Handling,Lua,Callstack,Implicit,Coroutine,我正在使用LuaCoroutines(Lua5.1)为应用程序创建插件系统。我希望使用协同程序,这样插件就可以像一个单独的应用程序一样运行,每个处理帧生成一次。插件程序通常遵循如下公式: function Program(P) -- setup -- NewDrawer(function() -- this gets rendered in a window for this plugin program -- drawstuff(howevery

我正在使用LuaCoroutines(Lua5.1)为应用程序创建插件系统。我希望使用协同程序,这样插件就可以像一个单独的应用程序一样运行,每个处理帧生成一次。插件程序通常遵循如下公式:

function Program(P)
    -- setup --
    NewDrawer(function()
        -- this gets rendered in a window for this plugin program --
        drawstuff(howeveryouwant)
    end)
    -- loop --
    local continue = true
    while continue do
        -- frame by frame stuff excluding rendering (handled by NewDrawer) --
        P = coroutine.yield()
    end
end
每个插件在应用程序的主循环中每帧恢复一次。然后,当绘图开始时,每个插件都有一个单独的窗口,在该窗口中,传递给NewDrawer的函数被执行

大概是这样的:

while MainContinue do
    -- other stuff left out --
    ExecutePluginFrames() -- all plugin coroutines resumed once

    BeginRendering()
    -- other stuff left out --
    RenderPluginWindows() -- functions passed to NewDrawer called.
    EndRendering()
end
然而,我发现,每当渲染中出现错误时,这会突然出现奇怪的行为,并破坏我原本健壮的错误处理系统。我花了一点时间才弄清楚发生了什么,但似乎对WIN:Draw()的调用(因为它是由主应用程序处理的)实际上导致了隐式跳转到协程的调用堆栈中

起初,问题是程序突然关闭,没有有用的错误输出。然后,在查看插件程序中定义的渲染函数的堆栈回溯后,我发现从主线程到窗口绘制的所有内容都不在那里,而结果在调用堆栈中

因为窗口是在线程和绘图函数中创建的,所以它们似乎是由该线程的调用堆栈处理的,这是一个问题,因为这意味着它们在主线程中设置的pcall之外


这会发生吗?这是C源代码中错误/快捷方式的结果吗?我是做错了什么,还是至少不够正确?有没有办法干净地处理这个问题?

我无法重现您描述的效果。这是我正在运行的代码:

local drawer = {}
function NewDrawer(func)
  table.insert(drawer, func)
end

function Program(P)
    NewDrawer(function()
        print("inside program", P)
    end)
    -- loop --
    local continue = true
    while continue do
        -- frame by frame stuff excluding rendering (handled by NewDrawer) --
        P = coroutine.yield()
    end
end

local coro = coroutine.create(Program)
local MainContinue = true
while MainContinue do
    -- other stuff left out --
    -- ExecutePluginFrames() -- all plugin coroutines resumed once
    coroutine.resume(coro, math.random(10))
    -- RenderPluginWindows() -- functions passed to NewDrawer called.
    for _, plugin in ipairs(drawer) do
      plugin()
    end
    MainContinue = false
end

当我逐步阅读代码并查看堆栈时,NewDrawer中设置的回调在“main”线程中被调用。如果调用返回当前线程的
coroutine.running()
,或者如果在主线程内,则调用
nil
,您可以自己看到它。

我已经发现了在我的情况下发生这种情况的原因。调用传递给NewDrawer的函数的渲染对象在创建时(由c代码)使用指向创建它们的lua状态的指针进行初始化,该指针用于访问其关联的lua数据和调用draw函数。我还没有看到卢厄州和合作项目之间的联系。因此,如果C代码导致函数产生,那么在产生函数后,可以在堆栈中调用函数


就解决方案而言,我决定将程序分为两个协同程序,一个用于渲染,一个用于处理。这通过允许渲染对象的创建线程也作为调用线程来解决问题,并保持了渲染循环和处理循环独立的优点。

由于您没有显示如何调用/恢复
程序,因此很难回答您的问题。您能简化代码以显示与应用程序其余部分的交互吗?添加了编辑,它位于RenderPluginWindows()中,调用堆栈中的隐式更改似乎正在发生。嗯,这正是预期的结果。我没想到这些事情会有什么不同,但这里有一些其他可能的原因:插件是在不同的环境中执行的。对传递给NewDrawer的绘图函数的调用是在C函数中进行的。C函数将一个完整的用户数据传递给它调用的函数,该函数是在插件程序中创建的。由于您不能共享代码供其他人执行,我认为您需要在resume/yield命令周围添加
print
语句,以及调用
coroutine.running()
以确定您看到的开关发生在何处。我经常使用协同程序(将其用于),但从未见过您描述的情况。