Skip to content

在工程线程中执行异步任务

Warning

The current page still doesn't have a translation for this language.

You can read it through google translate.

TaskLoop 简介

TaskLoop 是 SOUI 框架中的异步任务处理组件,它允许开发者将耗时操作放到后台线程中执行,避免阻塞 UI 线程,从而提升用户体验。

TaskLoop 核心接口

TaskLoop 组件的核心接口定义在 staskloop-i.h 文件中,主要包括两个结构体:

IRunnable 接口

IRunnable 是任务执行的基本接口,定义了任务对象需要实现的方法:

struct IRunnable
{
    virtual ~IRunnable() {}
    virtual IRunnable* clone() const = 0;
    virtual void run() = 0;
    virtual void *getObject() = 0;
    virtual const char *getClassInfo() const = 0;
};

各方法说明: - clone():克隆当前任务对象 - run():执行任务逻辑 - getObject():获取任务关联的对象 - getClassInfo():获取任务类信息

ITaskLoop 接口

ITaskLoop 是任务循环的核心接口,提供了任务管理的各种方法:

struct ITaskLoop : public IObjRef
{
    // 任务优先级枚举
    enum Priority
    {
        High = 1,    // 高优先级
        Normal = 0,  // 普通优先级
        Low = -1,    // 低优先级
    };

    /**
     * @brief 获取任务循环名称
     * @param pszBuf 缓冲区
     * @param nBufLen 缓冲区长度
     * @return 是否获取成功
     */
    virtual bool getName(char *pszBuf, int nBufLen) = 0;

    /**
     * @brief 启动任务循环线程
     * @param pszName 线程名称
     * @param priority 线程优先级
     */
    virtual void start(const char * pszName, Priority priority) = 0;

    /**
     * @brief 同步停止线程
     */
    virtual void stop() = 0;

    /**
     * @brief 提交任务到任务管理器
     * @param runnable 要运行的任务对象
     * @param waitUntilDone true 表示同步等待,false 表示异步提交
     * @param priority 任务优先级
     * @return 任务 ID,可用于取消任务
     */
    virtual long postTask(const IRunnable *runnable, bool waitUntilDone, int priority=0) = 0;

    /**
     * @brief 移除指定对象的所有待处理任务
     * @param object 指定对象
     */
    virtual void cancelTasksForObject(void *object) = 0;

    /**
     * @brief 取消指定 ID 的任务
     * @param taskId 任务 ID
     * @return 是否取消成功
     */
    virtual bool cancelTask(long taskId) = 0;

    /**
     * @brief 获取任务队列中的任务总数
     * @return 任务总数
     */
    virtual int getTaskCount() const = 0;

    /**
     * @brief 获取运行状态
     * @return 是否正在运行
     */
    virtual bool isRunning() = 0;

    /**
     * @brief 获取正在运行的任务信息
     * @param buf 接收任务信息的缓冲区
     * @param bufLen 缓冲区长度
     * @return false - 没有任务正在运行; true - 获取成功
     */
    virtual bool getRunningTaskInfo(char *buf, int bufLen) = 0;
};

使用方法

使用 TaskLoop 组件需要以下步骤:

1. 组件编译与创建

首先需要完成 TaskLoop 组件的编译,然后通过 SComMgr 来创建 TaskLoop 对象:

// 创建 TaskLoop 对象
CAutoRefPtr<ITaskLoop> pTaskLoop;
if (pComMgr->CreateTaskLoop((IObjRef**)&pTaskLoop))
{
    // 成功创建 TaskLoop 对象
}

2. 启动任务循环

创建 TaskLoop 对象后,需要调用 start 方法启动任务循环:

// 启动任务循环,名称为 "test",优先级为低
pTaskLoop->start("test", ITaskLoop::Low);

3. 提交任务

使用 postTask 方法提交任务到任务循环中:

// 提交任务
pTaskLoop->postTask(runnable, false, 0);

4. 停止任务循环

任务完成后,调用 stop 方法停止任务循环:

// 停止任务循环
pTaskLoop->stop();

任务优先级

TaskLoop 支持任务优先级管理:

  • 默认优先级为 0(Normal)
  • 可设置优先级为 High(1)、Normal(0)、Low(-1)
  • 任务插入队列时会根据优先级自动排序,优先级越大越靠前执行

任务创建辅助工具

SOUI 提供了 sfunctor.hpp 辅助头文件,可以方便地将对象的成员函数或全局函数转换为 IRunnable 对象。

使用示例

以下是一个完整的 TaskLoop 使用示例:

// 演示异步任务处理类
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 图片解码模块
    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;
}

最佳实践

  1. 结合 NotifyCenter 使用:在异步任务中需要通知 UI 层时,最好结合 SOUI 的 NotifyCenter 对象一起使用,这是最简单有效的方式。

  2. 合理设置优先级:根据任务的重要性和紧急程度合理设置任务优先级。

  3. 及时释放资源:任务完成后及时调用 stop 方法停止任务循环,释放相关资源。

  4. 错误处理:在实际应用中,需要添加适当的错误处理机制,确保程序的稳定性。

参考示例

更多使用示例可以参考 SOUI 的壁纸示例项目:demos/SouiWallPaper

通过合理使用 TaskLoop 组件,可以有效提升 SOUI 应用的性能和用户体验,特别是在处理网络请求、文件操作等耗时任务时。