• C/C++使用Lu脚本协程


    欢迎访问Lu程序设计

    C/C++使用Lu脚本协程

    1 说明

        要演示本文的例子,你必须下载Lu32脚本系统。本文的例子需要lu32.dll、lu32.lib、C格式的头文件lu32.h,相信你会找到并正确使用这几个文件。

        用C/C++编译器创建一个控制台应用程序,复制本文的例子代码直接编译运行即可。

    2 关于Lu协程

        在本教程系列的开始,介绍了Lu脚本的基本数据结构(详细参考Lu编程指南),即:

        如果Lu表达式(函数)中使用了函数yield,该表达式称为一个协程(coroutine)(详细参考Lu用户指南)。协程不能递归运行,只有这一个限制。Lu协程有4种状态:正常、运行、挂起、 终止。正常态是可以运行但还没有运行的状态;终止态协程是不能运行的,如果运行将返回nil。与协程相关函数有5个:

    yield     :挂起协程并立即返回表达式(函数)的值。
    status    :查询表达式(包含协程)的状态。
    abort     :中止挂起的协程,此时协程处于正常态。
    terminate :终止协程,协程处于终止态,不能运行。
    resume    :重启一个终止的协程,协程转为正常态。

        详细说明:

        (1)查询表达式(包含协程)状态 status(p)

        p是一个表达式句柄。正常返回一个整数表示表达式状态:0:普通表达式;1:普通表达式正在运行;2:普通表达式递归运行;5:协程;6:协程正在运行;7:协程挂起;8:协程终止。p非法时返回nil。

        (2)中止挂起的协程 abort(p)

        p是一个协程句柄,正处于挂起状态。协程中止后,可以再次从头开始执行。操作成功返回true,否则返回false。

        (3)终止协程 terminate(p)

        p是一个协程句柄,处于正常等待运行状态或者挂起状态。协程终止后将不能执行,执行时总返回nil。操作成功返回true,否则返回false。

        (4)重启一个终止的协程 resume(p)

        p是一个协程句柄,正处于终止状态,重启后可以运行。操作成功返回true,否则返回false。

        如果用C/C++编程,可以使用Lu核心库的输出函数ExMsgWithLu的4、8、9、10号功能操作协程。见下面的说明:

    void * _stdcall ExMsgWithLu(int Type,void *hMsg,void **Msg1,void **Msg2);    //C定义

        Type:输入参数,信息交换的类型。
       
    hMsg:输入参数,信息句柄,其意义取决于Type
       
    Msg1:该参数必须为变量,不能为常量。输入值及返回值取决于Type
       
    Msg2:该参数必须为变量,不能为常量。输入值及返回值取决于Type
        返回值:返回值的意义取决于
    Type

        说明:与Lu进行信息交换,向Lu传送信息或者从Lu获得信息。信息的类型及意义如下表所示:

    Type hMsg Msg1 Msg2 返回值 说明
    1 从二级函数获得的表达式句柄

    返回指向表达式模块号的指针

    返回表达式句柄 指向表达式名称的字符串指针 得到表达式名称、模块号、句柄
    2 编译表达式得到的表达式句柄

    返回指向表达式模块号的指针

    无意义 指向表达式名称的字符串指针 得到表达式名称、模块号
    3 luVOID类型指针,模块号 luVOID类型指针,返回模块中的表达式数目 无意义 无意义 得到模块中的表达式数目
    4 编译表达式得到的表达式句柄

    无意义

    无意义 将返回值取整数,表示表达式的状态。 返回值表示表达式状态:0:普通表达式;1:普通表达式正在运行;2:普通表达式递归运行;5:协程;6:协程正在运行;7:协程挂起;8:协程终止。
    5 无意义 无意义 无意义 无意义 清空缓冲池
    6 luIFOR类型指针,设置对象总数 luIFOR类型指针,返回以前设置的对象总数 无意义 无意义 设置对象(指针键)总数为多少时自动启动垃圾收集器GC。当*hMsg小于等于0时不会自动启动垃圾收集器。
    7 函数指针:void (_stdcall *GcEndCallMe)(void); 非0表示设置函数指针,0表示取消设置 无意义 非0表示操作成功。 设置一个函数GcEndCallMe,该函数将在垃圾收集器的最后调用。
    8 编译表达式得到的表达式句柄 无意义 无意义 非0表示操作成功。 中止正处于挂起状态的协程。协程中止后,可以再次从头开始执行。
    9 编译表达式得到的表达式句柄 无意义 无意义 非0表示操作成功。 终止处于正常等待运行状态或者挂起状态的协程。协程终止后将不能执行,执行时总返回nil。
    10 编译表达式得到的表达式句柄 无意义 无意义 非0表示操作成功。 重启一个终止的协程,重启后可以运行。

    3 代码

    代码1:最简单的协程

    #include <stdio.h>
    #include "lu32.h"
    #pragma comment( lib, "lu32.lib" )
    void main(void)
    {
    	void *hFor;		//存放表达式句柄,即脚本函数句柄
    	luINT nPara;		//存放表达式的自变量个数
    	LuData *pPara;		//存放输入自变量的数组指针
    	LuData Val;		//存放表达式的值
    	luINT ErrBegin,ErrEnd;	//表达式编译出错的初始位置和结束位置
    	int ErrCode;		//错误代码
    	wchar_t ForStr[]=L"f(x:i)= i=0, while{(i++, i<=5), yield(i)}, 888";	//字符串表达式
    	int i;
    	if(!InitLu()) return;	//初始化Lu
    	ErrCode=LuCom(ForStr,0,0,0,&hFor,&nPara,&pPara,&ErrBegin,&ErrEnd);	//编译表达式
    	if(ErrCode)
    	{
    		printf("表达式有错误!错误代码: %d 
    ",ErrCode);
    	}
    	else
    	{
    		for(i=0;i<8;i++)	//循环调用8次,观察每次调用的结果
    		{
    			Val=LuCal(hFor,pPara);	//计算表达式的值
    			if(Val.BType==luStaData_int64) printf("%I64d
    ",Val.x);
    		}
    	}
    	FreeLu();		//释放Lu
    }


    运行结果:

    1
    2
    3
    4
    5
    888
    1
    2

    代码2:协程状态转换

    #include <stdio.h>
    #include "lu32.h"
    #pragma comment( lib, "lu32.lib" )
    void main(void)
    {
    	void *hFor;		//存放表达式句柄,即脚本函数句柄
    	luINT nPara;		//存放表达式的自变量个数
    	LuData *pPara;		//存放输入自变量的数组指针
    	LuData Val;		//存放表达式的值
    	luINT ErrBegin,ErrEnd;	//表达式编译出错的初始位置和结束位置
    	int ErrCode;		//错误代码
    	void *Msg1, *Msg2;		//与Lu交换信息用
    	wchar_t ForStr[]=L"f(x:i)= i=0, while{(i++, i<=5), yield(i)}, 888";	//字符串表达式
    	if(!InitLu()) return;	//初始化Lu
    	ErrCode=LuCom(ForStr,0,0,0,&hFor,&nPara,&pPara,&ErrBegin,&ErrEnd);	//编译表达式
    	if(ErrCode)
    	{
    		printf("表达式有错误!错误代码: %d 
    ",ErrCode);
    	}
    	else
    	{
    		Val=LuCal(hFor,pPara);
    		if(Val.BType==luStaData_int64) printf("%I64d
    ",Val.x);
    		Val=LuCal(hFor,pPara);
    		if(Val.BType==luStaData_int64) printf("%I64d
    ",Val.x);
    		printf("协程状态 %d
    ",(int)ExMsgWithLu(4,hFor, &Msg1, &Msg2));
    		Val=LuCal(hFor,pPara);
    		if(Val.BType==luStaData_int64) printf("%I64d
    ",Val.x);
    		if(ExMsgWithLu(8,hFor, &Msg1, &Msg2)) printf("协程已中止!
    ");
    		Val=LuCal(hFor,pPara);
    		if(Val.BType==luStaData_int64) printf("%I64d
    ",Val.x);
    		if(ExMsgWithLu(9,hFor, &Msg1, &Msg2)) printf("协程已终止!
    ");
    		printf("协程状态 %d
    ",(int)ExMsgWithLu(4,hFor, &Msg1, &Msg2));
    		Val=LuCal(hFor,pPara);
    		if(Val.BType==luStaData_nil) printf("协程返回nil!
    ");
    		if(ExMsgWithLu(10,hFor, &Msg1, &Msg2)) printf("协程已重启!
    ");
    		Val=LuCal(hFor,pPara);
    		if(Val.BType==luStaData_int64) printf("%I64d
    ",Val.x);
    		Val=LuCal(hFor,pPara);
    		if(Val.BType==luStaData_int64) printf("%I64d
    ",Val.x);
    		Val=LuCal(hFor,pPara);
    		if(Val.BType==luStaData_int64) printf("%I64d
    ",Val.x);
    	}
    	FreeLu();		//释放Lu
    }


    运行结果:

    1
    2
    协程状态 7
    3
    协程已中止!
    1
    协程已终止!
    协程状态 8
    协程返回nil!
    协程已重启!
    1
    2
    3

    代码3:处理随机数的协程

    #include <stdio.h>
    #include <stdlib.h>
    #include <locale.h>
    #include "lu32.h"
    
    #pragma comment( lib, "lu32.lib" )
    
    void _stdcall LuMessage(wchar_t *pch) //输出动态库信息,该函数注册到Lu,由Lu二级函数调用
    {
    	wprintf(L"%s",pch);
    }
    
    //Lu脚本可调用的二级函数定义
    LuData _stdcall lu_rand(luINT mm,LuData *xx,void *vFor)	//生成0~9的随机数,通过参数返回
    {
    	xx[0].BType=luStaData_int64; xx[0].VType=luStaData_int64; xx[0].x = rand()%10;
    	xx[1].BType=luStaData_int64; xx[1].VType=luStaData_int64; xx[1].x = rand()%10;
    	return *xx;
    }
    
    void main(void)
    {
    	void *hSend,*hReceive1,*hReceive2;	//存放表达式句柄,即脚本函数句柄
    	luINT nPara;			//存放表达式的自变量个数
    	LuData *pPara;			//存放输入自变量的数组指针
    	LuData Para[2];			//存放表达式的参数
    	luINT ErrBegin,ErrEnd;	//表达式编译出错的初始位置和结束位置
    	luVOID k=0;				//32位平台上luVOID被定义为__int32;64位平台上luVOID被定义为__int64;k必须赋值为0
    	void *Msg1, *Msg2;		//与Lu交换信息用
    	wchar_t send[]=L"send(x,y)= while{true, rand(&x,&y), o{"\r\n*** send : ", x, "  ", y}, yield(0)}";	//生成数据的脚本函数
    	wchar_t receive1[]=L"receive1(x,y:a)= a=0, while{(a=a+(x+y), a< 30 ), o{"\r\n+++ receive1 : ", a}, yield(0)}";	//处理数据的脚本函数
    	wchar_t receive2[]=L"receive2(x,y:a)= a=0, while{(a=a+(x-y), a>(-10)), o{"\r\n--- receive2 : ", a}, yield(0)}";	//处理数据的脚本函数
    
    	srand(1);				//设置随机数的种子,改变该值可演示不同结果
    
    	setlocale(LC_ALL, "chs");	//设置可以输出中文
    
    	if(!InitLu()) return;	//初始化Lu
    
    	InsertKey((char *)&k,sizeof(luVOID),luPubKey_User,LuMessage,NULL,NULL,1,&Msg1);	//使Lu运行时可输出函数信息
    
    	SetFunction(L"rand",lu_rand,1);	//设置二级函数,有2个自变量参数
    
    	if(	LuCom(send,    0,0,0,&hSend,    &nPara,&pPara,&ErrBegin,&ErrEnd) ||			//编译表达式
    		LuCom(receive1,0,0,0,&hReceive1,&nPara,&pPara,&ErrBegin,&ErrEnd) ||
    		LuCom(receive2,0,0,0,&hReceive2,&nPara,&pPara,&ErrBegin,&ErrEnd))
    	{
    		printf("表达式有错误!
    ");
    	}
    	else
    	{
    		while(1)
    		{
    			LuCal(hSend,Para);			//运行协程hSend,产生数据,数据由Para返回
    
    			LuCal(hReceive1,Para);		//运行协程hReceive1,处理数据
    			if((int)ExMsgWithLu(4,hReceive1, &Msg1, &Msg2)==5)	//如果协程hReceive1结束
    			{
    				ExMsgWithLu(9,hReceive1, &Msg1, &Msg2);		//终止协程hReceive1
    			}
    
    			LuCal(hReceive2,Para);		//运行协程hReceive2,处理数据
    			if((int)ExMsgWithLu(4,hReceive2, &Msg1, &Msg2)==5)	//如果协程hReceive2结束
    			{
    				ExMsgWithLu(9,hReceive2, &Msg1, &Msg2);		//终止协程hReceive2
    			}
    
    			//如果协程hReceive1和hReceive2都终止
    			if((int)ExMsgWithLu(4,hReceive1, &Msg1, &Msg2)==8 && (int)ExMsgWithLu(4,hReceive2, &Msg1, &Msg2)==8)
    			{
    				ExMsgWithLu(9,hSend, &Msg1, &Msg2);			//终止协程hSend
    				break;
    			}
    		}
    	}
    
    	FreeLu();		//释放Lu
    }


    运行结果:

    *** send : 1 7
    +++ receive1 : 8
    --- receive2 : -6
    *** send : 4 0
    +++ receive1 : 12
    --- receive2 : -2
    *** send : 9 4
    +++ receive1 : 25
    --- receive2 : 3
    *** send : 8 8
    --- receive2 : 3
    *** send : 2 4
    --- receive2 : 1
    *** send : 5 5
    --- receive2 : 1
    *** send : 1 7
    --- receive2 : -5
    *** send : 1 1
    --- receive2 : -5
    *** send : 5 2
    --- receive2 : -2
    *** send : 7 6
    --- receive2 : -1
    *** send : 1 4
    --- receive2 : -4
    *** send : 2 3
    --- receive2 : -5
    *** send : 2 2
    --- receive2 : -5
    *** send : 1 6

    4函数说明

        本例用到了Lu的7个输出函数:初始化Lu的函数InitLu,释放Lu的函数FreeLu,编译表达式的函数LuCom、计算表达式的函数LuCal、注册C/C++函数的函数SetFunction、插入键值函数InsertKey、与Lu交换信息函数ExMsgWithLu。从这里查看这些函数的说明:Lu编程指南

    5 难点分析

        代码1和代码2较简单,这里仅对代码3做一下说明。

        代码3中用C/C++定义了一个函数lu_rand,注册到Lu系统由脚本调用(函数名为rand),用以产生随机数。另外,定义的3个脚本函数功能如下:

    send(x,y)= while{true, rand(&x,&y), o{" *** send : ", x, " ", y}, yield(0)}    //不断产生并输出随机数,然后挂起协程,随机数由参数x和y返回

    receive1(x,y:a)= a=0, while{(a=a+(x+y), a< 30 ), o{" +++ receive1 : ", a}, yield(0)}   //当执行a=a+(x+y), a< 30  时,输出a,然后挂起协程

    receive2(x,y:a)= a=0, while{(a=a+(x-y), a>(-10)), o{" --- receive2 : ", a}, yield(0)}  //当执行a=a+(x-y), a<(-10)时,输出a,然后挂起协程

    6 其他

        你可能注意到了,我的联系方式就在下面,如有不明之处或有什么建议,可随时与我进行联系。


    版权所有© Lu程序设计 2002-2013,保留所有权利
    E-mail: forcal@sina.com
      QQ:630715621
    最近更新: 2014年01月07日

  • 相关阅读:
    洛谷 P2920 [USACO08NOV]时间管理Time Management
    湖南测试 1
    洛谷 P1824 进击的奶牛
    4、map 和 tuple
    -_-#【Better JS Code】插入迭代值
    -_-#【JS】defer / async
    -_-#【JS】HTML5 API
    【jQuery】jQuery API 过 一 遍
    ♫【函数】函数声明 / 函数表达式
    -_-#【Mac】命令
  • 原文地址:https://www.cnblogs.com/riasky/p/3508982.html
Copyright © 2020-2023  润新知