背景:我正在使用Lua线程(协程)来处理来自stdin的用户输入(以允许程序在等待来自另一个FD的数据时暂停)。因为它是用户输入,如果不可能,则可能出现错误,例如:调用一个不存在的函数。
问题:是否可以恢复Lua线程以便我可以继续处理来自stdin的更多数据,或者我是否必须在每次错误后核对该线程并创建一个新线程?
这是我现在正在做的一些粗略的样本/伪代码:
while (1) {
select((max, &read_fds, &write_fds, NULL, NULL);
for each file descriptor {
if (read fd is set) {
read data into a buffer
if (current fd is stdin)
process_stdin()
else if (current fd is from server connection)
process_remote()
}
if (write fd is set) {
write data on non-blocking fd
}
}
}
process_stdin() {
status=luaL_loadbuffer(L, stdin_buf, len, "stdin");
if (status == LUA_ERRSYNTAX) {
/* handle EOF which means more user input needed
* or print error message for user, this works fine */
}
else if (status == 0) {
status=lua_resume(L, 0);
if (status != 0 && status != LUA_YIELD) {
/* Do I nuke the thread or is there another way to recover at this point??? */
}
}
}
通常,我会使用pcall
来捕获错误并恢复,但pcall
不支持5.1中的收益(尽管5.2可能是一个很好的解决方案)。通过lua_resume
调用,我在会话中遇到以下问题:
> no_such_func()
Error: attempt to call global 'no_such_func' (a nil value)
> print("hello world")
Error: cannot resume non-suspended coroutine
在第一个命令之后,线程状态设置为2(LUA_ERRRUN
)。
编辑:我收到的错误消息似乎不是因为展开的堆栈。我从ldo.c看到这条消息,表明问题是因为线程状态被设置为2。
if (L->status != LUA_YIELD && (L->status != 0 || L->ci != L->base_ci))
return resume_error(L, "cannot resume non-suspended coroutine");
所以我要么需要一种方法来重置状态,要么避免首先改变状态。我的猜测是,我可能会因为从我的主堆栈弹出线程并重新创建一个新线程,或升级到5.2所以我可以从pcall
得到。
答案 0 :(得分:1)
据我所知,抛出一个错误会将协同程序中的堆栈展开,这意味着没有函数可以跳回。 (参考手册对此没有任何说明。)
好像你必须创建一个新线程。
答案 1 :(得分:0)
对于Lua 5.1,您可以使用coxpcall。