μC/GUI-v3.90a学习笔记4--建立多任务的改进方法讨论
μC/OS-ii和μC/GUI结合,设立几个task,分别控制一个独立面板界面,将GUI_Exec()放入 μC/OS-ii系统的OS_TaskIdle()空闲进程中,这样当任何一个面板发生失效区域时,位于 OS_TaskIdle()空闲进程中的GUI_Exec()都能立即检测到,然后扫描GUI中创建的所有窗体的 WM__FirstWin单向链表,找到失效窗体hwin,并使用同步方式执行相应hwin的消息回调处理函数 完成当前GUI_Context上下文对应的各种图形属性的绘制操作,但是因为GUI_Lock()函数中, 已经将全局GUI_Context图形上下文恢复成了空闲进程idle()对应的GUI_Context内容, 所以本来是各个task进程分而治之的事情,确因"全局GUI_Context图形上下文"不能顺利恢复到 相应失效窗体hwin所在task专有的局部GUI_Context图像上下文,而不能达到"名副其实", 基本被架空,本来需要便利的地方,却没能实现便利,使得各个task不能专心于自身, 如果不进行代码修改,那么各个task自己设置的个性专属的GUI_Context图像上下文,就必须在每次 执行回调函数进行绘制之前,一个个的再手工设置回去,这显然不实际,因为控件自身的有很多 默认的回调函数,都是使用当前GUI上下文全局量GUI_Context,从这里来看μC/GUI代码本身 并没有很好的提供对多线程支持机制,最好在单线程中完成所有的工作,这样代码执行效率也高, 当然在多task中,如果一个task使用OSTimeDly()延时一段时间,让出cpu供其他task使用GUI, 那么延时到达之后,该task在调用GUI_Lock的时候就会恢复该task的对应的个性GUI_Context. 但是真正绘制时使用的绘制GUI_Context却是OS_TaskIdle()空闲进程task对应的GUI_Context, 所以在真正绘制的时候出现了不一致,引发了麻烦. void GUI_Lock(void) { if (_EntranceCnt == 0) { GUI_X_Lock();//占用资源 _TaskIDLock = GUI_X_GetTaskId();//当前task id号 } else { if (_TaskIDLock != GUI_X_GetTaskId()) { GUI_X_Lock();//如果另一个task需要使用资源,那么等待在这里, //直到_TaskIDLock对应的task解锁GUI_Unlock资源互斥 _TaskIDLock = GUI_X_GetTaskId();//本task获得执行机会,因为前一个task已经解锁, //所以此时_EntranceCnt=0 } } if (++_EntranceCnt == 1) { int TaskNo = _GetTaskNo();//==1时表示,新的task进程已经获得执行机会
if (TaskNo != _CurrentTaskNo) { if (_CurrentTaskNo>=0) {//与先前的task,对应的进程标识不同,那么保存,先前的,恢复现在的 _Save[_CurrentTaskNo].Context = GUI_Context;//保存先前的GUI上下文 GUI_Context = _Save[TaskNo].Context;//将当前task对应的GUI上下文恢复到全局量中 } _CurrentTaskNo = TaskNo; } } } 但是如果我们抛开代码执行效率,或者牺牲掉一些代码执行效率,并不会影响到我们的产品性能, 那么模块化实现μC/GUI就很有意义,因为那样的话每个task都认为自己独有一个自己的μC/GUI系统, 因为他们独有一个与自己task id对应的局部GUI_Context存储单元,能够很好的恢复现场. 所以首要解决的问题是:GUI_Exec()函数中失效窗体所属task对应的GUI_Context图形上下文如何恢复. 那么很自然的一种笨方式可以采用:在WM_Obj中添加一个GUI_Context类型指针GUI_CONTEXT *pcontext, 1. GUI_Exec()->GUI_Exec1()-> WM_LOCK();//锁住,资源互斥,防止其他进程执行其他抢占互斥资源 _DrawNext(); WM_UNLOCK(); 之后_DrawNext()->_Paint()->WM__ClipAtParentBorders()如果失效区域合法,那么在 WM_SelectWindow()函数之前加入我们的改变task对应GUI上下文指针的操作, GUI_Context = *pWin->pcontext;//添加的内容,恢复该win对应的task专有GUI上下文 2. 同样创建窗体过程如下: 控件创建时都会调用WM_CreateWindowAsChild()把自己登记到hParent上和WM__FirstWin单向链表中, 在_AddToLinList()之前加入:SetTaskGUI_Context(pWin); 它的具体实现如下: void SetTaskGUI_Context(WM_Obj* pWin) {int i; for(i = 0;i < GUI_MAXTASK;i++) {U32 TaskId = GUI_X_GetTaskId(); if(_Save[i].TaskID == TaskId) { pWin->pcontext = &_Save[i].Context; return; } } pWin->pcontext = &GUI_Context; } 3. 通过上面两个函数的添加基本可以了,以后所有的窗体创建操作都要在task进程内部来做, 同时为了能够正常运行,各个task进程执行代码的书写模式如下: void xxxx_thread(void *pdata) { Register_Task();//首先注册登记线程自己 //----------------------- //好了,下面xxxx_thread()进程就可以认为自己独占μC/GUI了 //以后遇到进程切换,GUI_Context会被保存到_Save[i].Context中, //同时当从其他进程切换到该xxxx_thread()进程时,GUI_Context也会从_Save[i].Context中恢复 GUI_Context就可以认为是该xxxx_thread()进程专用的了 for(;;) { ...μC/GUI中各种动态效果设置代码... } }
注: //首先向wm/WM.h结构体添加pcontext typedef struct { GUI_RECT Rect; /* outer dimensions of window */ GUI_RECT InvalidRect; /* invalid rectangle */ WM_CALLBACK* cb; /* ptr to notification callback */ WM_HWIN hNextLin; /* Next window in linear list */ WM_HWIN hParent; WM_HWIN hFirstChild; WM_HWIN hNext; U16 Status; /* Some status flags */ GUI_CONTEXT *pcontext;//添加 } WM_Obj; //1.向GUI/Core/GUITask.c添加代码如下 //-------------------------------------------------- //gliethttp--实现多线程下GUI的绘制独立性 #include "WM.h" extern U8 WM_IsActive; void SetTaskGUI_Context(WM_Obj* pWin) {int i; if(WM_IsActive) { for(i = 0;i < GUI_MAXTASK;i++) {U32 TaskId = GUI_X_GetTaskId(); if(_Save[i].TaskID == TaskId) { pWin->pcontext = &_Save[i].Context; return; } } } pWin->pcontext = &GUI_Context; } void Register_Task(void) { GUI_Lock();//注册登记进程对应的_Save[i].Context位置和相应的_Save[i].TaskID. GUI_Unlock(); } //2.向wm/WM.c->WM_CreateWindowAsChild()函数中添加 SetTaskGUI_Context(pWin);//添加的内容 _AddToLinList(hWin);//原有内容
//3.向wm/WM.c->_Paint()函数中添加 GUI_Context = *pWin->pcontext;//添加的内容,恢复该win对应的task专有GUI上下文 WM_SelectWindow(hWin);//原有内容
//4.最后一步:屏蔽wm/WM.c->WM_SetDefault()函数 void WM_SetDefault(void) { // GL_SetDefault(); // GUI_Context.WM__pUserClipRect = NULL; } 好了,修改工作已经全部完毕,以后多任务情况下,每个任务就可以不用担心绘制时候出问题了, 这时每个task才是真正意义上独占μC/GUI了.
改动的几个文件下载:μCGUI多任务改进尝试.rar
|