3

我在理解如何使用 luabind 正确使用协程时遇到了一些麻烦。有一个模板函数:

template<class Ret> 
Ret resume_function(object const& obj, ...)

其中 ( Ret) 应该包含yieldLua 传递给的值。

我目前的困惑点是:

  • 如果函数返回而不是调用会发生什么yield?是否resume_function返回函数的返回值?
  • 如果您不提前知道哪些(或多少)参数将被传递给,您应该如何使用此功能yield?例如,如果有多个可能的屈服函数,该函数可能会调用。
  • Ret如果将多个值传递给,则类型是yield什么?

我完全误解了这一切是如何运作的吗?我设想这样的事情。在 Lua 方面:

local img = loadImage("foo.png")

loadImage将是一个 C++ 函数,它请求将图像加载到不同的线程中,然后调用lua_yield,一段时间后作为参数调用luabind::resume_functionimg

我应该作为参数传递"foo.png"给吗?yield在我调用之前给一个不同的函数yield,然后从不将任何值传递给yield?构建这个的正确方法是什么?我显然在这里误解了一些东西。

4

1 回答 1

2

其中 (Ret) 应该包含 Lua 传递给 yield 的值。

Luabind 仅支持单个返回值,因此它只会返回传递给coroutine.yield.

如果函数返回而不是调用 yield 会发生什么?resume_function 是否返回函数的返回值?

是的,你得到了它的返回值。

如果您不提前知道哪些(或多少)参数将被传递给 yield,您应该如何使用此函数?例如,如果有多个可能的屈服函数,该函数可能会调用。

随你(由你决定; 它们是你的功能。您必须制定关于产生函数作为参数接收什么以及恢复协程的函数提供什么的约定。

如果将多个值传递给yield,Ret的类型是什么?

无论你想要什么。这是模板参数。函数的参数数量与函数提供的返回值无关。

记住:Lua 函数可以接受任意数量的参数并且可以返回任何值。Luabind 所能做的就是传递你给它的参数,并将 Lua 函数的返回值转换为你期望的返回值。Luabind 当然会对返回值进行类型检查。但是您有责任确保产生/返回的函数将返回可转换为用户为 Ret 提供的类型的内容。

loadImage 将是一个 C++ 函数,它请求将图像加载到不同的线程中,然后调用 lua_yield,一段时间后,使用 img 作为参数调用 luabind::resume_function。

如果您使用的是 Luabind,请不要lua_yield直接调用。在 Luabind 中 yield 的正确方法是向您注册的函数添加一个属性,该属性将在您从函数返回时产生。语法如下:

module(L)
[
    def("do_thing_that_takes_time", &do_thing_that_takes_time, yield)
];

也就是说,产生的 C++ 函数必须始终产生。这是 Luabind 的一个限制,与常规 Lua 一样,您可以根据需要选择是否屈服。

另外,不要忘记 Lua 协程与实际线程不同。他们不是先发制人的;只有当您明确告诉他们使用或等效的恢复调用时,它们才会执行。coroutine.resume

此外,你永远不应该从多个 C/C++ 线程运行同一个 Lua 实例;Lua 在同一个实例中不是线程安全的(这或多或少意味着同一个 lua_State 对象)。

您似乎想要做的是让 Lua 在 C++ 中调用某个函数,该函数本身会产生一个线程来执行某些过程,然后让 Lua 代码等到该线程完成然后收到它的答案。

为此,您需要为 Lua 脚本提供一个表示 C++ 线程的对象。所以你的loadImage函数不应该使用协程逻辑;它应该返回一个代表 C++ 线程的对象。Lua 脚本可以询问对象是否已完成,如果已完成,则可以从中查询数据。

协程可以在这里发挥作用的地方是如果您不希望 Lua 脚本等到完成。也就是说,你经常调用 Lua 脚本,但如果 C++ 线程没有完成,那么它应该只是返回。在这种情况下,您可以执行以下操作:

function loadImageAsCoroutine(imageFilename)
    local cppThread = cpp.loadImage(imageFilename);

    local function threadFunc(cppThread)
        if(cppThread:isFinished()) then
            local data = cppThread:GetImage();
            return data;
        else
            coroutine.yield();
        end
    end

    local thread = coroutine.create(threadFunc);

    local errors, data = assert(coroutine.resume(thread, cppThread));

    if(coroutine.status(thread) == "dead") then
        return data;
    else
        return thread;
    end
end

此函数返回协程图像数据本身。这个函数的调用者应该检查类型;如果类型是“线程”,那么 C++ 线程还没有完成。否则为图像数据。

这个函数的调用者可以用一些等价的coroutine.resume(无论是 luabind::resume_function 还是其他)来抽取他们想要的协程。每次检查返回值。nil如果 C++ 线程还没有完成,那将是,nil否则不会。

于 2011-06-16T04:05:43.560 回答