lua_resume():第二个参数的含义是什么?

时间:2016-06-05 17:18:11

标签: lua coroutine c-api

注意:下面有一些问题可以说明我的想法,但我唯一能找到的答案就是标题中实际问题的答案。不要求"一本书"在这里,或对所有这些的逐项回复。

我试图从C API启动一个协同程序,让它产生,并在以后继续它(可能在从其他协同程序执行恢复之后)。这是一个相当简单的用例,但lua_resume()的文档极其混乱:

  

int lua_resume(lua_State * L,lua_State * from,int nargs);

     

在给定的线程L中开始并恢复协程。

     

要启动协程,您可以将主要功能加上线程堆栈   任何论点;然后你调用lua_resume,其中nargs是数字   参数。当协程暂停或完成它时,此调用返回   执行。返回时,堆栈包含传递给的所有值   lua_yield,或者body函数返回的所有值。 lua_resume返回   LUA_YIELD如果协程产生,LUA_OK如果协程完成它   没有错误的执行,或者出错的错误代码(参见   lua_pcall)。

     

如果出现错误,堆栈未展开,因此您可以使用调试API   超过它。错误消息位于堆栈顶部。

     

要恢复协程,请删除最后一个lua_yield,put的所有结果   在它的堆栈上只有作为yield的结果传递的值,然后   叫lua_resume。

     

参数from表示正在恢复L的协程。如果有   没有这样的协程,这个参数可以是NULL。

"的含义代表正在恢复L"在这里非常不清楚。恰好是"来自" nil,Lfrom中的哪一个是"线程堆栈",以及恢复协程的确切要求是什么?可以在初始L和第二个实际恢复的状态之间修改状态lua_resume()吗?如果是这样,国家如何知道恢复哪些/什么功能?如果不是(即每个lua_State一个线程)什么是创建新线程的正确方法,以便它与父线程共享执行上下文(全局,环境等),以及正确的方法是什么在这种情况下调用lua_resume()并解除每次启动/恢复的呼叫?来自'来自'参数是否与这些事情相关?

最后,在任何一种情况下 - 如何在错误处理程序中获取完整的堆栈跟踪(例如,在lua_pcall错误时调用),这些错误处理程序尊重/知道跨越简历的调用? lua_getinfo()是否通过简历正确报告?这是'来自'论证是为了?

我真的很喜欢C API协程启动/恢复的完整,有效的例子,它说明了第二个参数的使用。关于要点的this example,但它已经过去了几年,而且自那时起API发生了变化 - lua_resume()现在有3个参数,而不是2 ...

1 个答案:

答案 0 :(得分:3)

  

当确切地说是“from”nil时,L和from中的哪一个是“线程堆栈”。

如果您询问from参数的{em>含义,it would appear that there isn't much of one。如果正在执行简历的C函数本身是从协程中调用的,那么只有使用它才有效。

L是您已将参数推送到其上的堆栈(以及启动函数,如果它是初始恢复调用)。所以这最适合术语“线程堆栈”。

  

恢复协程的确切要求是什么?

the docs for lua_status中所述,如果帖子的状态为LUA_OKLUA_YIELD,则可以恢复帖子。

请注意,恢复线程和恢复协程之间存在差异。 lua_resume恢复一个帖子。如果状态为LUA_OK,则没有活动协同程序,因此您正在创建协同程序,因此必须提供一个函数。如果线程是LUA_YIELD,则恢复线程将恢复生成的协程。

  

状态L是否可以在初始的lua_resume()和实际恢复的第二个之间进行修改?

当然可以; 必须是。毕竟,您将返回/收益率值作为推送到L的值。当你继续恢复它时,你必须删除这些值并将新值作为将从Lua的yield函数返回的值推送到堆栈上。

是的,你可以修改它。但是有关于你能做什么的规则。其中两个:

规则#1:你不能捅那些不属于你的东西。

让我们说Lua堆栈就像这样,就在你的初始简历之前(从左到右):

[A][B][C][F][1][2][3]

F是您要启动的功能。 1,2和3是参数。所以你传递3作为nargsABC只是您放入该堆栈的任意内容。

如果协同程序产生,你的堆栈看起来像这样:

[A][B][C][LOTS OF STUFF][a][b][c]

LOTS OF STUFF表示由协同程序处理创建的任意数量的堆栈数据。没有办法知道那里会有多少或多少。

abc是传递给Lua中yield的值。你可以随心所欲地玩它们。你甚至可以回到ABC,然后点击。

无法执行的操作是更改LOTS OF STUFF。该数据代表了屈服的协程状态。您不得更改它。完全没有。您可能也无法删除它下面的任何元素。因此,您无法删除ABC

规则#2:您必须准确恢复堆栈停止的位置。

协程产生后,你可以从堆栈中删除一些东西并添加东西(根据规则#1)。所以我们假设堆栈看起来像这样:

[A][B][C][LOTS OF STUFF][a][Q][R][D]

a是原始返回值之一,其他内容是您在此期间创建的临时值。所以现在是恢复协程的时候了。你有一些新的参数要传递,1和2.你怎么做?

你的第一步必须来清理你的烂摊子。您必须将堆栈返回到此点:

[A][B][C][LOTS OF STUFF]

完成后,您可以按1和2,然后以nargs为2恢复协程。

  

如果是这样,状态如何知道恢复哪个/什么功能?

上面的LOTS OF STUFF部分告诉它“恢复的位置/功能”。

  

创建新线程的正确方法是什么,以便它与父线程共享执行上下文(全局,环境等)

“执行上下文”与线程无关。这些东西与函数相关联,而不是线程。因此,如果您希望函数与其他函数共享相同的环境,那么它们应该与该函数共享相同的环境。

这些功能如何执行(协同与否)与其环境无关。

  

最后,在任何一种情况下 - 如何在错误处理程序中获取完整的堆栈跟踪(例如,在lua_pcall错误时调用),它尊重/意识到简历中的调用?

你不能。

lua_resume由于错误而失败时,它会在堆栈上留下信息,以跟踪简历和发出错误的位置之间发生的情况。但它不能知道简历本身是如何发生的。这是你必须要做的事情,取决于你开始时如何恢复该协程。

from字段的目的是将resumer连接到已恢复的。