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.
它是为了满足多个任务同时执行的要求。在 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.