SOUI是一套开源(MIT协议)的Windows平台下的DirectUI框架,它提供了大量的高效控件,也提供了很多扩展组件,目前已经持续维护近10年,在大量的项目中证明稳定可靠。
GIT地址:
国内:https://gitee.com/setoutsoft/soui
国外:https://github.com/soui2/soui
下面介绍一个最近增加的组件:TaskLoop.
TaskLoop是一个异步任务模块。对于有网络请求的情况,异步任务是常规需求。
和使用其它SOUI组件一样,要使用异步任务模块,先完成组件的编译,然后就可以通过SComMgr来创建TaskLoop对象。
打开soui.08.sln可以看到上面工程组织结构。使用其它版本VS的朋友,可以用build.bat来生成自己需要的VS版本。
我们先看一看staskloop-i.h中的接口定义。
1 #pragma once 2 #include <unknown/obj-ref-i.h> 3 4 namespace SOUI 5 { 6 struct IRunnable 7 { 8 virtual ~IRunnable() {} 9 virtual IRunnable* clone() const = 0; 10 virtual void run() = 0; 11 virtual void *getObject() = 0; 12 virtual const char *getClassInfo() const = 0; 13 }; 14 15 struct ITaskLoop : public IObjRef 16 { 17 enum Priority 18 { 19 High = 1, 20 Normal = 0, 21 Low = -1, 22 }; 23 24 virtual bool getName(char *pszBuf, int nBufLen) = 0; 25 26 /** 27 * Start a thread to run. 28 * @param priority the thread priority 29 */ 30 virtual void start(const char * pszName,Priority priority) = 0; 31 32 /** 33 * Stop thread synchronized. 34 */ 35 virtual void stop() = 0; 36 37 /** 38 * postTask post or send a tasks to this task manager. 39 * @param runnable the to be run task object. 40 * @param waitUntilDone, true for send and false for post. 41 * @param priority, the task priority. 42 * @return the task id, can be used by cancelTask. 43 */ 44 virtual long postTask(const IRunnable *runnable, bool waitUntilDone, int priority=0) = 0; 45 46 /** 47 * Remove tasks for a specific object from task loop pending task list 48 * @param object the specific object wants pending functors to be removed 49 */ 50 virtual void cancelTasksForObject(void *object) = 0; 51 52 /** 53 * Cancel tasks for a specific task ID list 54 * @param taskList the task ID list to be canceled 55 * @return the removed task list. 56 */ 57 virtual bool cancelTask(long taskId) = 0; 58 59 /** 60 * get the total task number in the task loop queue. 61 * @return total task number in task loop queue 62 */ 63 virtual int getTaskCount() const = 0; 64 65 /** 66 * get the run loop status. 67 * @return the running status 68 */ 69 virtual bool isRunning() = 0; 70 71 /** 72 * get the running task info. 73 * @param buf, to receive task info buf. 74 * @param bufLen, buffer length 75 * @return false - no task is running; true - succeed. 76 */ 77 virtual bool getRunningTaskInfo(char *buf, int bufLen) = 0; 78 }; 79 }
创建出ITaskLoop接口后,先调用start来启动,再调用postTask来添加一个异步任务。添加到同一个TaskLoop对象中的任务顺序在同一个线程中执行。
任务的优先级默认是0,如果很多任务在排除,新加入的任务希望优先执行,则将nPriority这个参数设置为一个更大的值,任务插入队列的时候,自动根据nPriority排序,nPriority越大,排序越前。
postTask需要提供一个IRunnable对象来运行。
使用SOUI/helper/sfunctor.hpp可以方便的将一个对象的成员函数或者全局函数转换成为一个IRunnable对象。
下面看一下demo中如何使用ITaskLoop.
//演示异步任务。 class CAsyncTaskObj { public: void task1(int a) { SLOG_INFO("task1,a:" << a); } void task2(int a, const std::string & b) { SLOG_INFO("task2,a:" << a<<" b:"<<b.c_str()); } }; int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE /*hPrevInstance*/, LPTSTR /*lpstrCmdLine*/, int /*nCmdShow*/) { //必须要调用OleInitialize来初始化运行环境 HRESULT hRes = OleInitialize(NULL); SASSERT(SUCCEEDED(hRes)); //使用imgdecoder-png图片解码模块演示apng动画 SComMgr2 *pComMgr = new SComMgr2(_T("imgdecoder-png")); { //演示异步任务。 CAutoRefPtr<ITaskLoop> pTaskLoop; if (pComMgr->CreateTaskLoop((IObjRef**)&pTaskLoop)) { CAsyncTaskObj obj; pTaskLoop->start("test", ITaskLoop::Low); STaskHelper::post(pTaskLoop, &obj, &CAsyncTaskObj::task1, 100,true); STaskHelper::post(pTaskLoop, &obj, &CAsyncTaskObj::task2, 100,"abc", true); pTaskLoop->stop(); pTaskLoop = NULL; } } //.... return 0; }
注:
demo为了方便演示实际上是在工作线程中使用了同步等待。
使用TaskLoop最好结合SOUI的NotifyCenter对象一起使用,在异步任务中需要通知UI层,使用NotifyCenter是最简单有效的。
更多用法参考SOUI的壁纸demo: https://github.com/soui-demo/SouiWallPaper
启程软件 2019-02-03