免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
12下一页
最近访问板块 发新帖
查看: 5802 | 回复: 11
打印 上一主题 下一主题

[C] 如何在Lua5.1.4中实现这样的效果 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2013-01-25 15:12 |只看该作者 |倒序浏览
本帖最后由 converse 于 2013-01-25 15:14 编辑

模拟一个场景,在C中创建出coroutine来执行Lua脚本,并且提供C API给Lua使用,当某些操作可能会阻塞时(如网络I/O),C函数中执行yield将协程切换出去,然后未来的某个时刻,如果条件满足则resume继续执行后面的脚本.我写了个demo程序是这样的:

co.c:
  1. #include <stdio.h>
  2. #include "lua.h"
  3. #include "lualib.h"
  4. #include "lauxlib.h"

  5. static int panic(lua_State *state) {
  6.   printf("PANIC: unprotected error in call to Lua API (%s)\n", lua_tostring(state, -1));
  7.   return 0;
  8. }

  9. static int test(lua_State *state) {
  10.   printf("in test\n");
  11.   lua_yield(state, 0);
  12.   printf("after in test\n");
  13.   return 0;
  14. }

  15. int main(int argc, char *argv[]) {
  16.   char *name = NULL;
  17.   name = "co.lua";
  18.   lua_State*  L1 = NULL;
  19.   L1 = lua_open();
  20.   lua_atpanic(L1, panic);
  21.   luaL_openlibs( L1 );

  22.   lua_register(L1, "test", test);
  23.   lua_State*  L = lua_newthread(L1);

  24.   luaL_dofile(L, name);
  25.   sleep(1);
  26.   lua_resume(L, 0);
  27.   printf("after resume test\n");

  28.   return 0;
  29. }
复制代码
co.lua
  1. print("before")
  2. test("123")
  3. print("after resume")
复制代码
问题在于,resume之后,在co.lua中的"after resume"没有打印出来

论坛徽章:
0
2 [报告]
发表于 2013-01-25 15:13 |只看该作者
@starwing83 来看看.

论坛徽章:
4
水瓶座
日期:2013-09-06 12:27:30摩羯座
日期:2013-09-28 14:07:46处女座
日期:2013-10-24 14:25:01酉鸡
日期:2014-04-07 11:54:15
3 [报告]
发表于 2013-01-25 15:59 |只看该作者
static int test(lua_State *state) {
  printf("in test\n");
  lua_yield(state, 0);
  printf("after in test\n");
  return 0;
}

很明显错了, return lua_yield(state, 0)

论坛徽章:
5
狮子座
日期:2013-08-20 10:12:24午马
日期:2013-11-23 18:04:102015年辞旧岁徽章
日期:2015-03-03 16:54:152015亚冠之德黑兰石油
日期:2015-06-29 18:11:1115-16赛季CBA联赛之新疆
日期:2024-02-21 10:00:53
4 [报告]
发表于 2013-01-25 16:45 |只看该作者
要达到这样的效果,在Lua5.2里面直接用yieldk即可。但是如果是5.1,那么需要满足下面的条件:

1. 你知道所有resume的地方。
2. 暗中yield的函数不会被递归调用。

达到这两个条件,我们就可以继续了。

实现方法其实非常简单。每一个函数由两个函数组成,一个是你的test,一个是你的test_cont,当准备yield之前,先做这样的一个操作:

conts[coroutine.running()] = test_cont

然后调用lua_yield(其实所有的操作未必需要C模块,Lua模块完全可以做得到)。

在resume之前,判断conts里面对应需要resume的coroutine有没有对应的cont,如果有,就将其push上coroutine,pcall之。然后用其结果resume。

这样就能达到楼主想要的效果了。

因为一个coroutine肯定只会有一个地方被断(不然就不止一个了= =),所以同一时间的continuation也应该只有一个才对。应该是不会出现问题的。
第二步resume前那个需要push函数然后pcall的部分,可能需要C模块来做,但是其实Lua模块也做得了——那样就没啥意义了= =你可以直接在yield后面写你想执行的代码,不必要绕这么大的湾……

本质上,Lua5.2只是帮你自动管理了这个表,如是而已……

论坛徽章:
0
5 [报告]
发表于 2013-01-25 16:51 |只看该作者
回复 4# starwing83

直接调用lua_yield,会报错:
attempt to yield across metamethod/C-call boundary


   

论坛徽章:
4
水瓶座
日期:2013-09-06 12:27:30摩羯座
日期:2013-09-28 14:07:46处女座
日期:2013-10-24 14:25:01酉鸡
日期:2014-04-07 11:54:15
6 [报告]
发表于 2013-01-25 17:00 |只看该作者
楼主可以让test函数返回一个continue的函数以及其他返回值, 主线程再次resume就行了.

converse 发表于 2013-01-25 16:51
回复 4# starwing83

直接调用lua_yield,会报错:

论坛徽章:
5
狮子座
日期:2013-08-20 10:12:24午马
日期:2013-11-23 18:04:102015年辞旧岁徽章
日期:2015-03-03 16:54:152015亚冠之德黑兰石油
日期:2015-06-29 18:11:1115-16赛季CBA联赛之新疆
日期:2024-02-21 10:00:53
7 [报告]
发表于 2013-01-25 17:04 |只看该作者
回复 5# converse


    所以要有对框架的完全控制能力才行啊,你必须保证yield和resume在同一个层次去做(都在C,或者都在Lua),不然就是错。

最简单的还是升级到5.2,5.1的coroutine毕竟有限制……

论坛徽章:
5
狮子座
日期:2013-08-20 10:12:24午马
日期:2013-11-23 18:04:102015年辞旧岁徽章
日期:2015-03-03 16:54:152015亚冠之德黑兰石油
日期:2015-06-29 18:11:1115-16赛季CBA联赛之新疆
日期:2024-02-21 10:00:53
8 [报告]
发表于 2013-01-25 17:06 |只看该作者
回复 6# linux_c_py_php


    你觉得resume会直接调用栈顶函数?

不会的。

Lua有两个完全独立的栈。一个叫做数据栈,就是你平时看到的push/to所在的那个栈。还有一个隐藏着的,每coroutine的,不参与垃圾回收的叫做CallInfo栈。这个栈保存了每次函数调用的信息。所以,必须push到coroutine上面pcall,返回什么的是没有效果的……

论坛徽章:
4
水瓶座
日期:2013-09-06 12:27:30摩羯座
日期:2013-09-28 14:07:46处女座
日期:2013-10-24 14:25:01酉鸡
日期:2014-04-07 11:54:15
9 [报告]
发表于 2013-01-25 17:07 |只看该作者
这样貌似也不一定行.

linux_c_py_php 发表于 2013-01-25 17:00
楼主可以让test函数返回一个continue的函数以及其他返回值, 主线程再次resume就行了.

论坛徽章:
0
10 [报告]
发表于 2013-01-25 17:07 |只看该作者
回复 7# starwing83


我自己做的项目,完全把控是没有问题的.

也能保证yield和resume都在同一层C/Lua来进行操作,但是就是上面的例子中,yield/resume都在C层做,但是还是出错的.你可否简单的改成正确的结果我看看?


   
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP