我正在尝试从C API启动协程,让它产生,并在以后继续它(可能在从其他协同程序执行恢复之后).这是一个相当简单的用例,但是lua_resume()的文档非常混乱:
int lua_resume (lua_State *L, lua_State *from, int nargs);
Starts and resumes a coroutine in the given thread L.
To start a coroutine, you push onto the thread stack the main function plus
any arguments; then you call lua_resume, with nargs being the number of
arguments. This call returns when the coroutine suspends or finishes its
execution. When it returns, the stack contains all values passed to
lua_yield, or all values returned by the body function. lua_resume returns
LUA_YIELD if the coroutine yields, LUA_OK if the coroutine finishes its
execution without errors, or an error code in case of errors (see
lua_pcall).In case of errors, the stack is not unwound, so you can use the debug API
over it. The error message is on the top of the stack.To resume a coroutine, you remove any results from the last lua_yield, put
on its stack only the values to be passed as results from yield, and then
call lua_resume.The parameter from represents the coroutine that is resuming L. If there is
no such coroutine, this parameter can be NULL.
“代表正在恢复L的协程”的含义在这里非常不清楚.当确切地说是“来自”nil时,L和from中的哪一个是“线程堆栈”,以及恢复协程的确切要求是什么?可以在初始的lua_resume()和实际恢复的第二个之间修改状态L吗?如果是这样,国家如何知道恢复哪些/什么功能?如果不是(即每个lua_State一个线程)创建新线程的正确方法是什么,以便它与父线程共享执行上下文(全局,环境等),以及调用lua_resume的正确方法是什么( )并在这种情况下解除每个开始/恢复的呼叫? ‘from’参数可以与这些东西相关吗?
最后,在任何一种情况下 – 如何在错误处理程序中获取完整的堆栈跟踪(例如,在lua_pcall错误时调用),它尊重/知道跨越简历的调用? lua_getinfo()是否通过简历正确报告?那是’from’论证的意思吗?
我真的很喜欢C API的协程启动/恢复的完整,有效的例子,它说明了第二个参数的使用.要点上有this example,但它已经存在多年了,自那时起API发生了变化 – 现在lua_resume()接受3个参数,而不是2个…
When exactly is “from” nil, which of L and from are the “thread stack”.
如果你问的是from参数的含义,it would appear that there isn’t much of one.如果正在执行简历的C函数本身是从协程中调用的,那么它才有效.
L是您已将参数推送到其上的堆栈(以及启动函数,如果它是初始恢复调用).所以这最适合术语“线程堆栈”.
what are the exact requirements for resuming a coroutine?
如the docs for lua_status
中所述,如果线程的状态为LUA_OK或LUA_YIELD,则可以恢复线程.
请注意,恢复线程和恢复协程之间存在差异. lua_resume恢复一个帖子.如果状态为LUA_OK,则没有活动协程,因此您正在创建新的协程,因此必须提供一个函数.如果线程是LUA_YIELD,则恢复线程将恢复生成的协程.
Can the state L be modified between the initial lua_resume() and the second one which is actually resuming?
当然可以;它一定要是.毕竟,当你去恢复它时,你得到返回/屈服值.当你去恢复它时,你必须删除这些值并将新值作为将从Lua的yield函数返回的值推送到堆栈.
所以是的,你可以修改它.但是有关于你能做什么的规则.他们两个人:
规则#1:你不能捅那些不属于你的东西.
假设Lua堆栈在您的初始简历(从左到右)之前看起来像这样:
[A][B][C][F][1][2][3]
F是您要启动的功能. 1,2和3是参数.所以你传递3作为nargs. A,B和C只是放在堆栈上的任意东西.
如果协同程序产生,你的堆栈看起来像这样:
[A][B][C][LOTS OF STUFF][a][b][c]
很多STUFF表示由协程处理创建的任意数量的堆栈数据.没有办法知道那里会有多少或多少.
a,b和c是Lua中传递给yield的值.你可以随心所欲地玩它们.您甚至可以回到A,B和C处.
你不能做的是改变很多东西.该数据代表了屈服的协程状态.您不得更改它.完全没有.您可能也无法删除它下面的任何元素.所以你不能删除A,B或C.
规则#2:您必须准确恢复堆栈停止的位置.
协同程序产生后,您可以从堆栈中删除一些东西并添加内容(根据规则#1).所以我们假设堆栈看起来像这样:
[A][B][C][LOTS OF STUFF][a][Q][R][D]
a是原始返回值之一,其他内容是您在此期间创建的临时值.所以现在是恢复协程的时候了.你有一些新的参数要通过,1和2.你怎么做?
你的第一步必须是清理你的烂摊子.您必须将堆栈返回到此点:
[A][B][C][LOTS OF STUFF]
一旦完成,你可以按1和2,然后恢复coroutine,其中nargs为2.
If so, how does the state know where/what function to resume?
上面的LOTS OF STUFF部分告诉它“恢复哪里/什么功能”.
what is the proper way to create a new thread, so that it shares an execution context (globals, environment, etc) with the parent thread
“执行上下文”与线程无关.那些东西与功能有关,而不是线程.因此,如果您希望函数与其他函数共享相同的环境,那么它们应该与该函数共享相同的环境.
这些函数的执行方式(协程与否)与其环境无关.
And finally, in either case – how can I get a full stack trace for debugging in an error handler (for example invoked on error from lua_pcall) which respects / is aware of calls across resumes?
你不能.
当lua_resume由于错误而失败时,它会在堆栈上留下信息,以跟踪简历和发出错误的位置之间发生的情况.但它无法知道简历本身是如何发生的.这是你必须要做的事情,这取决于你如何重新开始那个协程开始.
from字段的目的不是将resumer连接到resume.