事件标志是一个用来实现同步的对象,由多个位组成,用作指示对应事件存在的标志。事件标志由用来指示对应事件存在的位模式(bitpattern)和一个等待事件标志的任务队列组成。
uTenux提供了一组API用于处理事件标志:创建、删除、设置、等待、清除。
1、创建事件标志:tk_cre_flg
为建立的事件标志分配一个控制块
事件结构体:
typedef struct t_cflg { VP exinf; /* 事件标志扩展信息 */ ATR flgatr; /* 事件标志的属性 */ UINT iflgptn; /* 事件标志的初始值 */ UB dsname[8]; /* 对象名,没啥用*/ } T_CFLG;
其中事件属性flgatr,可设置为以下的一个或多个值:
TA_TFIFO 任务按FIFO的顺序排队
TA_TPRI 任务按优先级顺序排队
TA_WSGL 不允许等待多个任务(等待一个任务)
TA_WMUL 允许等待多个任务(等待多个任务)
TA_DSNME 设定DS对象名
OS根据事件标志的属性对使用这个事件标志的任务进行调度。
或等待:等待任意一个条件满足,与等待:等待所有条件满足
我的理解,事件标志就是一个二进制数。因为事件标志本身就是个UINT类型的数字。设置事件标志就是将这个数的某一位置位,清除事件标志就是将这个数的某一位清零。同一个事件标志有多个位,多个任务可以同时使用一个事件标志。
创建事件标志,OS会建立一个事件标志的控制块,用于调度。创建事件标志的时候,会为这个时间标志设置个初始值:iflgtn。与任务和信号量相同,FlgID只是这个事件标志的代表,并不是事件标志的值。
事件标志的属性中如果TA_WMUL设置为1,那么就允许多个任务同时等待一个事件标志。当一个事件标志被设置时,如果多个任务都满足条件,此时这些任务都会被释放。进入等待状态,有系统调度决定哪个先执行哪个后执行。
2、设置和清除时间标志
ER ercd= tk_set_flg(ID flgid,UINT setptn) ; ER ercd= tk_clr_flg(ID flgid,UINT clrptn);
给出事件标志的ID,和要设置的位,即可设置或清除事件标志。
如果一个调用tk_wai_flg的任务的等待状态释放条件满足,则该任务的等待状态被清除。即此时OS的事件分派器工作了。
3、等待事件标志:
ERercd= tk_wai_flg(ID flgid,UINT waiptn,UINT wfmode,UINT* p_flgptn,TMO tmout);
等待flgid的某些位被置位。如果条件不满足,则进入等待状态。
关于API的详细描述,uTenux内核规范有详细介绍。
【实验描述】
1、创建一个事件标志:FlgID,FlgID事件标志的初始值设置为1. 如果初始值iflgtn被设置为0x02,那么TaskB将先执行一遍循环,然后进入等待后TaskA开始执行。
2、创建两个优先级相同的任务:EventflagSampleTaskA(TaskA)EventflagSampleTaskB(TaskB)
3、创建任务后启动TaskB,在TaskB中启动TaskA。此时由于TaskB的优先权较大,TaskB继续执行,遇到等待事件标志时候停止执行。此时TaskA开始执行。
4、TaskA首先为TaskB设置事件标志(0x02),然后申请事件标志Flag的0x01。条件满足,继续执行清除这个事件标志(0x01)。循环执行,重新等待事件标志,此时事件标志没有被设置,所以TaskA进入休眠状态。TaskB继续执行。
5、TaskB获得优先权开始执行,完成FlagID(0x02)的清除,之后继续等待资格事件。当然,同样没等到进入休眠,任务A继续。
6、如此往复。。。
【实验代码】
#include "EventflagSample.h" void EventflagSampleTaskA(W stacd,VP exinf); void EventflagSampleTaskB(W stacd,VP exinf); void EventflagSamplePutFlg(void); static ID TaskID_A; static ID TaskID_B; static ID FlgID; EXPORT ER EventflagSample( void ) { T_CTSK ctsk; T_CFLG cflg; cflg.exinf = (VP) NULL; //没有额外信息 cflg.flgatr = TA_WMUL | TA_TPRI; //事件标志的属性 cflg.iflgptn = 0x01; //事件标志的初始值 FlgID = tk_cre_flg(&cflg); if(FlgID < E_OK) { return FlgID; } else { tm_putstring((UB*)"成功创建事件标志\n"); } ctsk.bufptr = (VP)NULL; ctsk.exinf = (VP) NULL; ctsk.task = EventflagSampleTaskA; ctsk.stksz = 512; ctsk.itskpri = 24; ctsk.tskatr = TA_HLNG | TA_RNG0; TaskID_A = tk_cre_tsk(&ctsk); if(TaskID_A < E_OK) { return TaskID_A; } else { tm_putstring("成功创建任务A\n"); } ctsk.task = EventflagSampleTaskB; ctsk.itskpri = 24; TaskID_B = tk_cre_tsk(&ctsk); if(TaskID_B < E_OK) { tm_putstring((UB*)"创建任务B出错\n"); return TaskID_B; } else { tm_putstring("成功创建任务B\n"); } tm_putstring("启动任务B\n"); tk_sta_tsk(TaskID_B,5); return E_OK; } void EventflagSampleTaskA(W stacd,VP exinf) { UINT flgptn; while(1) { tm_putstring((UB*)"任务A循环开始\n"); tk_set_flg(FlgID,0x02); //为任务B设置事件标志 tk_wai_flg(FlgID,0x01,TWF_ANDW,&flgptn,-1); EventflagSamplePutFlg(); tm_putstring((UB*)"\n"); tk_clr_flg(FlgID,0x01); //清除任务A自己的事件标志 EventflagSamplePutFlg(); //输出任务信息:3:两个事件标志都被设置,2:任务B事件标志被设置,1:任务A事件标志被设置 tm_putstring((UB*)"TaskAEnd\n"); } } void EventflagSampleTaskB(W stacd,VP exinf) { UINT flgptn; tm_putstring((UB*)"任务B启动任务A\n"); tk_sta_tsk(TaskID_A,0); while(1) { tm_putstring((UB*)"任务B循环开始\n"); tk_set_flg(FlgID,0x01); //为任务A设置事件标志 tk_wai_flg(FlgID,0x02,TWF_ANDW,&flgptn,-1); EventflagSamplePutFlg(); tm_putstring((UB*)"\n"); tk_clr_flg(FlgID,0x02); //清除自己的事件标志 EventflagSamplePutFlg(); tm_putstring((UB*)"TaskBEnd\n"); } while(1); } void EventflagSamplePutFlg(void) { B flgptn[10]; T_RFLG rflg; tm_putstring((UB*)"Now Flag pattern is 0x0000000"); tk_ref_flg(FlgID, &rflg); ltostr(rflg.flgptn,flgptn,16,10); tm_putstring((UB*)flgptn); tm_putstring((UB*)"\n"); }
【实验输出】
----------------------------------------------------
micro Tenux Version 1.6.00(build 0180)
Supported MCU is ST STM32F407VG
Copyright(c) 2008-2013 by Dalian uLoong Co.,Ltd.
----------------------------------------------------
成功创建事件标志
成功创建任务A
成功创建任务B
启动任务B
任务B启动任务A
任务B循环开始
任务A循环开始
Now Flag pattern is 0x00000003
Now Flag pattern is 0x00000001
TaskAEnd
任务A循环开始
Now Flag pattern is 0x00000003
Now Flag pattern is 0x00000001
TaskAEnd
任务A循环开始
Now Flag pattern is 0x00000003
Now Flag pattern is 0x00000001
TaskAEnd
任务A循环开始
Now Flag pattern is 0x00000003
Now Flag pattern is 0x00000001
TaskAEnd
任务A循环开始
Now Flag pattern is 0x00000003
Now Flag pattern is 0x00000001
TaskAEnd
任务A循环开始
Now Flag pattern is 0x00000003
Now Flag pattern is 0x00000001
TaskAEnd
任务A循环开始
Now Flag pattern is 0x00000003
Now Flag pattern is 0x00000001
TaskAEnd
任务A循环开始
Now Flag pattern is 0x00000003
Now Flag pattern is 0x00000001
TaskAEnd
任务A循环开始
Now Flag pattern is 0x00000003
Now Flag pattern is 0x00000001
TaskAEnd
任务A循环开始
Now Flag pattern is 0x00000003
Now Flag pattern is 0x00000001
TaskAEnd
任务A循环开始
Now Flag pattern is 0x00000003
Now Flag pattern is 0x00000001
........................
【总结】
事件标志应该是为了等待两个任务同步而设立的。每个任务完成一定的工作之后,通过事件标志通知另一个任务可以执行了。从而使得两个任务之间协调完成一项工作。