【转】Symbian OS — 活动对象和活动规划器

原文:http://blog.sina.com.cn/s/blog_448367c901009zua.html~type=v5_one&label=rela_prevarticle

活动对象(Active Objects)和活动规划器(Active Scheduler)

 

一、概述

    在Symbian OS 中,活动对象和活动规划器提供了非抢占式多任务,用来取代多线程,简化了程序、提高了CPU 的效率。

 

二、多任务

1、 多任务定义

    多任务是操作系统中使用的一种技术,用于处理器在同一时间处理多个工作。在协作式多任务下,正在运行的任务决定何时放弃CPU 的使用权;在抢占式多任务下,系统的规划器将当前任务运行固定时间片段后挂起。在这两种情况下,规划器负责选择下一个将要运行的任务并运行它。

    多线程就是每个线程处理一个任务,所有线程共享一个CPU ,这种设计要求CPU 以最小时间间隔在多个线程间切换。实现多线程时,需要多线程之间尽可能的共享系统执行环境。这样就减少了CPU 在切换线程时,存储和恢复的状态信息。

 

2、Symbian OS 多任务

    Symbian OS 实现了抢占式多任务(多线程),所以它能够多个应用程序和服务器同时运行。而非抢占式多任务是在同一个线程上的活动对象间实现的。如下图所示:

    Symbian OS 中,线程间的时间规划是自动的。程序员只需要创建一个线程并安排它要执行的工作。系统规划器自动为每个线程分配CPU 的时间。线程间的切换非常频繁,就好像多个任务在同时进行。

    一个线程可以有一个活动规划器来分配活动对象的执行时间。活动对象好比是线程的子任务。但是,活动规划器使用非抢占式: 一个正在运行的活动对象是不能挂起的,当它完成任务后才将控制权交给活动规划器,活动规划器再选择下一个执行的活动对象。

    通常情况下,线程上已经有了一个创建好的活动规划器,程序员可以直接使用活动对象。例如UI 应用程序有一个已创建了活动规划器的主线程。但是,当创建新线程时,必须显式的建立活动规划器后,才能使用活动对象。活动对象最常见的使用就是处理事件。例如,应用程序框架使用活动对象来处理按键事件和屏幕更新。

 

3、 客户/服务器架构和异步方法

    Symbian OS拥有一个 客户/服务器模式的微型内核架构。通常所设计的应用程序都是使用了服务器资源的客户端应用程序。服务器通常提供一个R- 类作为服务器端服务的代理或句柄。

    R- 类有两种成员方法:

    异步方法: 客户端调用这个方法,创建一条消息并发送给服务器端。当消息发送完成,客户端线程从这个方法中返回。服务器端有它自己的线程捕获该消息,并处理这个请求。当服务器端完成这个请求后,通知发送请求的客户端线程,并传递一个完成代码作为标记。客户端线程必须处理这个通知。

    同步方法: 消息发送和服务器端处理与异步方法相似。但是,客户端线程调用这个同步方法后,不会立即返回,它将挂起线程,直到从服务器端接受到请求完成的通知。当服务器端响应了客户端请求,Symbian OS 唤醒挂起的客户端线程。然后,客户端线程处理这个通知。

    当调用同步方法时,客户端线程将被挂起,直到收到服务器端的完成通知。在许多情况下,客户端程序必须更新UI 和处理用户输入事件。如果同步方法等待太长时间,用户的请求将得不到及时的反馈。当应用程序使用异步方法时,客户端线程能够及时的在服务器处理请求的过程中处理事件和更新UI 。当服务器端接受了请求,客户端将收到完成通知。在这种情况下,用户的使用体验将很流畅。Symbian OS 提供了一种框架很容易的实现了异步服务: 活动对象和活动规划器。

    异步方式与同步方式的不同能够很容易的通过TRequestStatus 参数进行区别。异步方式必须拥有一个TRequestStatus 参数,这个参数存储了服务器的完成通知。

 

三、活动对象和活动规划器

1、活动对象

    Symbian OS 是基于微型内核架构的,通常使用异步接口来访问服务器。活动对象和活动规划器提供了一种简便的框架来使用异步服务:活动对象发送异步请求和处理完成通知,它用一个变量来指示服务器的完成通知。活动规划器监视每个活动对象,当发现一个活动对象的请求得到了处理,它将执行这个活动对象的RunL()方法来处理服务器完成通知。一个活动对象只能实现一个异步请求。然而,可以通过RunL()方法中发布一个新的异步请求,并使活动对象处于活动状态。活动规划器将能够再次调用这个RunL()方法。

    一个继承自CActive 的类称为活动对象。CActive 的声明如下 :    
class CActive : public CBase
{
public:

    //任务优先级
    enum TPriority
    {
    EPriorityIdle=-100,
    EPriorityLow=-20,
    EPriorityStandard=0,
    EPriorityUserInput=10,
    EPriorityHigh=20,
    };
public:
    IMPORT_C ~CActive();

    //取消异步服务,将调用DoCancel()
    IMPORT_C void Cancel();

    //从活动规划器中移除活动对象
    IMPORT_C void Deque();

    //重新设定任务优先级
    IMPORT_C void SetPriority(TInt aPriority);

    //活动对象的请求是否响应

    inline TBool IsActive() const;

    //活动对象是否添加进了活动规划器
    inline TBool IsAdded() const;

    //获得任务的优先级
    inline TInt Priority() const;
protected:

    //构造函数
    IMPORT_C CActive(TInt aPriority);

    //使活动对象处于活动状态
    IMPORT_C void SetActive();
 // Pure virtual

    //在派生类中实现具体的取消过程,通过Cancel()调用,不要显式调用。
    virtual void DoCancel() =0;

    //在派生类中实现具体的请求完成的处理工作
    virtual void RunL() =0;

    //处理RunL()的任何异常退出
    IMPORT_C virtual TInt RunError(TInt aError);

public:

    //请求状态
    TRequestStatus iStatus;
private:
    TBool iActive;
    TPriQueLink iLink;
    friend class CActiveScheduler;
    friend class CServer;
    friend class CServer2;
};

 

    活动对象的编写步骤:

    1、 创建一个活动对象(CActive派生类)。

    2、封装适当的异步服务提供器句柄(通常是R-类),作为类的数据成员。

    3、活动对象的构造函数中调用CActive的构造函数,同时指定适当的任务优先级,通常为默认优先级。

    4、在ConstructL()中连接到服务提供器,并调用CActiveScheduler::Add()将活动对象添加到活动规划器中。

    5、按正常方式实现NewL()和NewLC()。

    6、实现异步请求函数,通常名为Start()或StartL()。在异步请求函数中调用适当的异步服务函数。最后调用SetActive()使活动对象处于活动状态。

    7、实现RunL()方法,用于在请求完成时处理必要的工作。

    8、实现DoCancel()方法以处理取消请求。通常只是在服务提供器句柄上调用适当的取消函数。

    9、重写RunError()方法,处理RunL()的任何异常退出。默认实现将造成严重错误。

    10、在活动对象的析构函数中,调用Cancel()并关闭服务提供器。

    活动对象的使用步骤:

    1、通过适当的NewL()或NewLC()创建活动对象的实例。

    2、调用Start()或任何发送请求函数。

    3、如果希望在服务器处理请求前取消请求,调用Cancel()。

 

    为了正确的使用活动对象,理解一些活动对象的性质和行为是很有帮助的。

    状态 。当一个活动对象调用了一个异步方法,它发送iStatus 参数。服务提供器立即设置这个这个参数为KRequestPending ,这说明服务提供器将要处理这个请求。

    活动性 。当一个活动对象发送了一个异步请求,它必须用SetActive() 方法使活动对象处于活动状态。这是因为活动规划器只管理处于活动状态的活动对象。只用当活动规划器调用RunL() 方法或程序员显式调用Cancel() 方法,活动对象的状态才从活动变为非活动。

    优先级 。活动规划器是以活动对象的优先级进行管理的。活动对象的优先级是在构造时指定的。当活动对象处于非活动状态时,可以通过SetPriority() 改变优先级。

    结果处理 。当一个活动对象处于活动状态,并且它的iStatus 数据成员不是KRequestPending ,这意味着服务提供器已经完成了活动对象的请求。当活动规划器发现这样的活动对象时,将使之处于非活动状态并调用它的RunL() 方法。RunL() 方法是一个纯虚方法,因此需要在派生类中具体实现。RunL() 可以实现为任意工作,但不能运行时间过长。

    取消请求 。活动对象正在请求的异步服务必须能够取消。当Cancel() 方法被调用,活动规划器将调用DoCancel() 方法并且是活动对象处于非活动状态。DoCancel() 方法是一个纯虚函数,因此必须在派生类中具体实现取消正在请求异步服务的工作。

    错误处理 。当活动对象的RunL() 方法执行时异常退出,那么活动规划器将调用活动对象的RunError() 方法,并传递一个异常代码参数。如果RunError() 方法返回非零值,当前线程的活动规划器将产生严重错误。RunError() 方法是一个虚方法,可以重写。默认实现是返回系统传递给它的错误代码。

 

2、活动规划器

    在Symbian OS 中,每个进程都用一个主线程。主线程能够为进程创建新线程。如果使用活动对象,必须在线程上安装活动规划器。

    Symbian OS 的UI 应用程序是一个有主线程的进程。应用程序框架为主线程安装了活动规划器,并且在活动规划器中有许多处理应用程序事件(按键事件和屏幕更新请求) 的活动对象。程序员可以使用由应用程序框架提供的活动规划器。但是,如果程序员创建了一个新的线程,程序员必须自己为新线程安装、启动和删除活动规划器。

    使用活动规划器:

    1、创建一个活动规划器实例,并且使用CActiveScheduler::InStall()方法将活动规划器安装在线程中。

    2、创建一个活动对象并使用CActiveScheduler::Add()方法添加进活动规划器中。

    3、发送一个或多个异步请求 。

    4、使用CActiveScheduler::Start()方法启动活动规划器 。

    活动规划器启动后将不会停止,直到调用Stop()方法。停止活动规划器,必须在一个活动对象中调用CActiveScheduler::Stop()方法,然后,调用了活动规划器的CActiveScheduler::Start()方法的函数才返回。在启动活动规划器前,必须在规划器中添加活动对象并且至少发送一个异步请求。否则线程将会挂起。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值