现在的位置: 首页 > 综合 > 正文

AO 框架简介

2013年10月31日 ⁄ 综合 ⁄ 共 2735字 ⁄ 字号 评论关闭
Active Object (AO) 框架,是 Symbian 的 基本工作部分。
它是为了满足多个任务同时执行的要求。在 Windows/Unix 平台上,我们可以不加
思索的使用多线程来完成多任务。可是在嵌入式平台上,系统的资源是有限的。比如
CPU, 内存,都比我们平时用的个人计算机要低。这就要求嵌入式系统能够合理的
使用系统资源。不能频繁的切换线程或者进程。
Symbian 为这种特别需求设计了 Active Object (AO)框架.AO 框架是运行于一个
线程内部的调度框架。其基本思想就是把一个单线程分为多个时间片,来运行不同的任务。
这和多线程有很大区别。多线程之间是可以被抢占的(由操作系统调度),但是AO框架
中的各个任务是不可被抢占的。一个任务必须完成,才能开始下一个任务。

多线程和AO框架的比较:

多线程                           AO框架
可以被抢占                        不可被抢占
上下文切换耗费CPU时间                没有上下文切换
由操作系统调度                        由线程自己的AO框架调度
每个线程都有至少4K Stack.                AO没有单独的 Stack.
操作系统还要分配额外的资源记录线程        只是一个 Active Object.

Symbian 系统本身使用了大量的 AO 框架来实现一些系统服务。这使得 Symbian
和其他嵌入式系统相比较,对系统资源的使用更加合理。

AO 框架包括 CActiveScheduler 和 CActive (Active Object). 一个线程的
所有的 Active Object 都被安装在 CActiveScheduler. CActiveScheduler
监控每个 Active Object 是否完成了当前任务,如果完成了,就调度下一个 Active
Object来执行。CActiveScheduler也根据优先级来调度各个 Active Object.

关于 CActiveScheduler 的创建和安装,CActive 的创建和安装,和 CActive
的任务处理,可以参看 SDK 文档。理解起来不难。下面要说一个比较容易忽略的地方。
这对理解 AO 框架非常重要。

创建调度器:
CActiveScheduler * scheduler = new (ELeave) CActiveScheduler;
CleanupStack::PushL(scheduler);
CActiveScheduler::Install(scheduler); //看这里1

运行调度器:
CActiveScheduler::Start(); //看这里2

停止调度器:
CActiveScheduler::Stop();  //看这里3

以上代码都是运行在一个线程中的,一般来讲,一个EXE只有一个主线程. 可是如果真的有
2个线程呢? 每个线程都有自己的 CActiveScheduler, 那么这个CActiveScheduler 类
是怎么调用 CActiveScheduler::Start(), CActiveScheduler::Stop() 来运行/停止
当前的调度器的? 为什么在当前线程下调用 CActiveScheduler::Start(),
CActiveScheduler::Stop() 运行/停止的是当前线程的 调度器而不是 另一个线程的调度器?
我们看到 Start/Stop并没有参数.

打开 CActiveScheduler 的类定义看,它并没有静态的 成员来表示线程.

class CActiveScheduler : public CBase
        {
public:
        IMPORT_C CActiveScheduler();
        IMPORT_C ~CActiveScheduler();
        IMPORT_C static void Install(CActiveScheduler* aScheduler);
        IMPORT_C static CActiveScheduler* Current();
        IMPORT_C static void Add(CActive* anActive);
        IMPORT_C static void Start();
        IMPORT_C static void Stop();
        IMPORT_C static TBool RunIfReady(TInt& aError, TInt aMinimumPriority);
        IMPORT_C static CActiveScheduler* Replace(CActiveScheduler* aNewActiveScheduler);
        IMPORT_C virtual void WaitForAnyRequest();
        IMPORT_C virtual void Error(TInt anError) const;
private:
        void DoStart();
        void OwnedStartLoop(TInt& aRunning);
        IMPORT_C virtual void OnStarting();
        IMPORT_C virtual void OnStopping();
        IMPORT_C virtual void Reserved_1();
        IMPORT_C virtual void Reserved_2();
private:
        // private interface used through by CActiveSchedulerWait objects
        friend class CActiveSchedulerWait;
        static void OwnedStart(CActiveSchedulerWait& aOwner);
protected:
        inline TInt Level() const;
private:
        TInt iLevel;
        TPriQue<CActive> iActiveQ;
        };

但是我们看到有一个static函数 CActiveScheduler* Current(); 返回当前线程的调度器.
奥秘就在这个函数是怎么实现的. 这个静态的函数怎么就能得到当前这个运行线程的调度器,而不是
别的线程的调度器.我们可以猜想,肯定是Current()内部实现能取到当前线程的标识信息.用这个
标识,静态函数能取到这个线程的 CActiveScheduler.

答案,当前线程的线程 ID可以这样得到:

创建一个缺省的线程对象 :
RThread thread;
取得当前线程的ID:
TThreadId threadId = thread.Id();

能得到当前线程的threadId,当然可以得到和当前线程关联的 CActiveScheduler.

抱歉!评论已关闭.