2011-06-16 72 views
3

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

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

凡(Ret)应该包含由Lua中传递给yield值。

我的困惑的当前点是:

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

我只是完全错误地认为这一切是如何工作的?我想像这样。在Lua的一面:

local img = loadImage("foo.png") 

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

我应该通过"foo.png"yield作为参数吗?在我拨打yield之前转到不同的功能,然后从不将任何值传递给yield?什么是正确的方式来构建这个?我显然在这里误解了一些东西。

回答

2

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

Luabind只支持单个返回值,所以它只会返回传递给coroutine.yield的第一个值。

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

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

如果您事先不知道将要传递哪些(或多少)参数,您应该如何使用此函数?例如,如果存在多个可能的屈服函数,则该函数可以调用。

这取决于你;他们是你的功能。您必须制定关于屈服函数作为参数接收的约定,以及恢复协程的函数提供了什么。

如果传递多个值以产生Ret,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

+0

谢谢。答案的前半部分非常有帮助。但是我认为,下半年不是解决这个问题的最好方法(投票很少)。在你的输入中,我想我的头脑中有一张如何编写一个适当的协程调度程序的图片,它允许这种阻塞调用按我喜欢的方式工作。 – Xtapolapocetl 2011-06-16 04:20:04

+0

事实上,我已经做到了。这很复杂,但我现在可以从Lua做出这样的阻塞呼叫,而没有额外的复杂性或者轮询。谢谢你的帮助! – Xtapolapocetl 2011-06-16 21:22:01