如何恢复一个Lua线程(协程)时处理错误 [英] How to handle errors when resuming a Lua thread (coroutine)

查看:1334
本文介绍了如何恢复一个Lua线程(协程)时处理错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

背景:我用一个Lua线程(协程)来处理从标准输入用户输入(允许程序,而在等待数据从另一个FD暂停)。因为这是用户的输入,错误是可能的,如果没有可能的,例如调用一个不存在的功能。

问:能否Lua的线程被恢复,这样我可以继续处理从标准输入更多的数据,或者我有核弹线程和创建的每一个错误后,一个新的

这里是什么我现在做一些粗略的采样/伪code:

 而(1){
  选择((最大值,&安培; read_fds,&安培; write_fds,NULL,NULL);
  每个文件描述符{
    如果(读FD设置){
      数据读入缓冲器
      如果(当前fd被STDIN)
        process_stdin()
      否则,如果(当前fd是从服务器连接)
        process_remote()
    }
    如果(写FD设置){
      写非阻塞FD数据
    }
  }
}process_stdin(){
  状态= luaL_loadbuffer(L,stdin_buf,LEN,标准输入);
  如果(状态== LUA_ERRSYNTAX){
    / *手柄EOF这意味着需要更多的用户输入
     *或用户打印错误消息,这工作正常* /
  }
  否则,如果(状态== 0){
    状态= lua_resume(L,0);
    如果(状态= 0&安培;!&安培;!=状态LUA_YIELD){
      / *我是否核弹线程或有另一种方式在这一点上恢复? * /
    }
  }
}

通常情况下,我会使用 PCALL 来捕获错误并恢复,但 PCALL 不支持收益率在5.1(5.2虽然可以在这里很好的解决方案)。随着 lua_resume 电话,我遇到了我的会话如下:

 > no_such_func()
错误:试图调用全球'no_such_func'(一个零值)
>打印(世界你好)
错误:无法恢复非暂停协程

第一个命令后,线程状态设置为2( LUA_ERRRUN )。

编辑:我越来越没有出现是因为展开堆栈的错误消息。我是从ldo.c这表明问题是因为线程状态越来越设置为2看到此消息。

 如果(1→!状态= LUA_YIELD&放大器;及(1→状态= 0 || 1→!CI = 1→base_ci) )
      返回resume_error(L,不能恢复非暂停协程);

所以,我要么需要一种方法来重置状态或避免在首位的状态变化。我的猜测是,我可能会弹出线程关闭我的主要堆栈并重新创建一个新的,或升级到5.2,所以我可以从产生 PCALL

解决方案

有关的Lua 5.1,可以使用 coxpcall

Background: I'm using a Lua thread (coroutine) to process user input from stdin (to allow the program to pause while waiting on data from another FD). Because it's user input, errors are possible if not probable, e.g. calling a non-existent function.

Question: Can the Lua thread be recovered so that I can continue to process more data from stdin, or do I have to nuke the thread and create a new one after every error?

Here's some rough sample/pseudo code of what I'm doing now:

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??? */
    }
  }
}

Typically, I would use pcall to catch the error and recover, but pcall doesn't support the yield in 5.1 (though 5.2 may be a good solution here). With the lua_resume call, I'm running into the following in my session:

> no_such_func()
Error: attempt to call global 'no_such_func' (a nil value)
> print("hello world")
Error: cannot resume non-suspended coroutine

After the first command, the thread status is set to 2 (LUA_ERRRUN).

Edit: the error message I'm getting doesn't appear to be because of the unwound stack. I'm seeing this message from ldo.c which indicates the issue is because the thread state is getting set to 2.

  if (L->status != LUA_YIELD && (L->status != 0 || L->ci != L->base_ci))
      return resume_error(L, "cannot resume non-suspended coroutine");

So I either need a way to reset the state or avoid having the state change in the first place. My guess is that I may be stuck with popping the thread off my main stack and recreating a new one, or upgrading to 5.2 so I can yield from a pcall.

解决方案

For Lua 5.1, you can use coxpcall.

这篇关于如何恢复一个Lua线程(协程)时处理错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆