Luabind和协同程序

时间:2011-06-16 00:57:58

标签: lua coroutine luabind

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

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

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

我目前的困惑点是:

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

我完全错误地认为这一切是如何运作的?我想象这样的事情。在Lua方面:

local img = loadImage("foo.png")

loadImage将是一个C ++函数,它请求将图像加载到另一个线程中,然后调用lua_yield,稍后luabind::resume_function调用img作为参数。

我应该将"foo.png"作为参数传递给yield吗?在致电yield之前使用其他功能,然后再将任何值传递给yield?什么是正确的结构方式?我显然在这里误解了一些东西。

1 个答案:

答案 0 :(得分: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中生成的正确方法是向您注册的函数添加一个属性,无论何时从函数返回,它都会产生。语法如下:

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还是其他)来抽取他们想要的协程。每次都检查返回值。如果C ++线程尚未完成,则为nil,否则为nil