symbian中活动对象的一些简单的使用 和 Symbian平台移植之——活动规划器CActiveScheduler的灵活应用

symbian中活动对象的一些简单的使用 和 Symbian平台移植之——活动规划器CActiveScheduler的灵活应用
原文地址:http://blog.csdn.net/suyouxin/archive/2005/01/06/242759.aspx
 symbian中活动服务对象的一些简单的使用

对symbain的学习已经又几个月了,今天来写写自己的一些活动服务对象使用方法.

symbian官方推荐使用活动服务对象(CActive)来代替多线程的使用,我想这个道理是很明了的,在手机这样的小内存设备里,运行多线程的程序是非常耗资源的,为了节约资源,symbian提供了一个活动服务对象的框架,允许把程序里并发执行对象(其实不是并发,不过宏观上看来是)放在一个线程里面执行,这些并发工作的对象就通过活动规划器(ActiveScheduler)来进行管理.

关于这两个东西的介绍,网上有一大堆的文档,我就不在这里废话了,如何使用呢?这里我先举一个简单的计数器的例子.我选择写一个exe的程序,也就是说程序是以E32Main为入口的.
    
GLDEF_C TInt E32Main() 
{
     CTrapCleanup* cleanup=CTrapCleanup::New();
     TRAPD(error,callInstanceL()); 
     if (error != KErrNone){
         printf("get error %d\r\n", error);
     }
     delete cleanup; 
     return 0; 
}

以上的内容是每一个exe文件都应该做的,CTrapCleanup* cleanup=CTrapCleanup::New()建立一个清除堆栈,以便程序在异常退出的时候把清除堆栈里面的资源都释放掉.当然你也可以加上堆检测宏,这里我就不多说了.TRAPD是symbian里面经常使用的宏,功能类似于try,第一个参数是让定义一个错误返回值变量的名字, 后面就是可能有异常的你写的函数.当这个函数异常时,程序不会crash, 你可以得到异常的原因.可以参考nokia论坛上的一些关于这些使用的文档.

接下来是vcallInstanceL函数,在这个函数里面我来建立ActiveScheduler.

LOCAL_C void callInstanceL() 
{
     CActiveScheduler* scheduler = new(ELeave) CActiveScheduler();
     CleanupStack::PushL(scheduler);
     CActiveScheduler::Install(scheduler);
     TRAPD(error,doInstanceL());
     if(error) {
          printf("error code=%d\r\n",error);
     }
     else {
          printf("OK!\r\n[press any key]");
     }
     CleanupStack::PopAndDestroy(scheduler);
}

这段程序很简单就是创建一个活动规划器,并压入清除栈,然后安装活动规划器,这样就可以用了.再执行真正的实例函数,最后出栈销毁.doinstanceL我们放到最后来写,现在来构造我们的活动计数器对象.

class TimeCount : public CActive
    {
public :
     static TimeCount* NewLC(); // 构造函数
     ~TimeCount();
     void StartL();              // 计数开始
     void ConstructL(); 
     void RunL();               // 延时事件到达以后的处理函数
     void DoCancel();        // 取消请求提交
     void setDelayTime(int delayTime);
private:
     TimeCount();
     RTimer iTimer;            // 定时器
     int iTimeCount;            // 计数器
     int mTime;                   // 计数间隔时间 单位秒
};

TimeCount::TimeCount() 
 : CActive(0)                    // 这里可以设置活动对象的优先级
{
     // 把自己加入活动规划器
     CActiveScheduler::Add(this);
}

TimeCount* TimeCount::NewLC()
{
     TimeCount* result = new (ELeave) TimeCount();
     CleanupStack::PushL( result );
     result->ConstructL();
     return result;
}

void TimeCount::DoCancel(void)
{
     iTimer.Cancel();
}

void TimeCount::setDelayTime(int mTime)
{
     DelayTime = mTime;
}

TimeCount::~TimeCount()
{
     Cancel();
     iTimer.Close();
}

void TimeCount::StartL()
{
     // 设定定时器状态为每隔mTime秒钟状态完成一次
     iTimer.After(iStatus, 10000 * 100 * mTime);
     // 提交异步请求
     SetActive();
}

void TimeCount::ConstructL()
{
     // 初始化计数器和定时器
     iTimeCount = 0;
     User::LeaveIfError(iTimer.CreateLocal());
}

void TimeCount::RunL()
{
     // 计数器+1以后继续提交延时请求事件
     printf("The Count is ->>%d", iTimeCount++);
     StartL();
}

每一个活动服务对象都有一个iStatus来标识当前对象的状态.在这里我们把iStatus设定为iTimer.After(iStatus, 10000 * 100 * mTime);也就是定时器定时mTime秒钟以后iStatus发生改变,这个时候活动规划器会收到这个状态的改变,从而调用相应活动对象的处理函数,也就是RunL函数.在RunL函数里面进行计数和输出,然后调用startL重新设置定时器和对象状态,再提交给活动规划器.这样mTime秒钟以后活动规划器会再次调用RunL函数.一直这样重复,这样就达到了计数器的效果.

最后我们来写doinstanceL函数
LOCAL_C void doInstanceL()
{       
     TimeCount* timeCount = TimeCount::NewLC();
     // 每隔一秒钟打印一次
     TimeCount->setDelayTime(1);
     TimeCount->StartL();
 
     CActiveScheduler::Start();
 
     CleanupStack::PopAndDestroy(1); 
}

创建好对象以后,加上CActiveScheduler::Start()程序就开始运行了,这句话告诉活动规划器该等待对象的状态的改变了,在这里就是timeCount的iStatus的改变.等iStatus改变并调用了RunL以后,继续等待iStstus的改变,这样我们使用活动对象的计数器就能够通过消息驱动运行起来了.

这里的CActiveScheduler只管理了一个CActive对象,就是timeCount,可以用类似的方法实现多个CActive,并且都加入CActiveScheduler,CActiveScheduler将会等待所有加入它的CActive的状态的改变,其中有一个的状态改变就会去执行对应的活动对象的处理函数,当状态同时发生的时候,会通过对象的优先级来决定先调用谁的RunL函数.CActiveScheduler也是非抢占式的,当一个RunL函数还没有执行完的时候,如果另一个CActive的状态改变,会等待RunL执行完以后再执行另一个CActive的处理函数.

用起来还算简单吧?.



本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/suyouxin/archive/2005/01/06/242759.aspx

原文地址:http://blog.csdn.net/alex_hua/archive/2008/07/10/2633137.aspx
由于做工程的移植工作,需要移植代码到Symbian平台上,但之前代码的架构与Symbian平台看起来是有冲突,体现在之前代码中有一个独立线程用来做事件驱动、分发,然后在事件回调中完成自己的逻辑(包括异步请求),该线程是用

    while(1)

    {

        getevent();

        dispatchevent()

    }

来实现。但在Symbian平台上,所有的异步方法的侦测是通过CActiveScheduler.Start()完成,且该方法实际上就是一个死循环。这样看起来,在同一个线程中,是不可能有两个死循环存在的,这个移植是不能完成的,除非修改代码架构。

    这个问题确实困扰了很久,呵呵,因为是一个人开发,确实没有人可以帮忙出点主义,脑子也死了,想不开了。现在终于有眉目了,基本可以解决该问题,途径就是理解活动对象和活动规划器的原理,灵活应用这对活宝!

    之前一直想着,为了能侦测到异步请求是否完成,CActiveScheduler.Start()这个方法必须在线程的初始就调用,其实可以不这样,CActiveScheduler.Start()在线程的任何地方随时可以调用,且CActiveScheduler起来后,还是可以侦测到“很久”以前就完成的异步请求。例子如下:

 

/*  ============================================================================ 

 Name  : NewClassTest.h  Author   : Alex  Version  : 1.0  Copyright   : su-fun  Description : CNewClassTest declaration  ============================================================================  */

 

#ifndef NEWCLASSTEST_H 

#define NEWCLASSTEST_H

#include <e32base.h> 

// For CActive, link against: euser.lib 

#include <e32std.h>  

//For RTimer, link against: euser.lib 

 

class CNewClassTest : public CActive 


public:  

    // Cancel and destroy  

    ~CNewClassTest();

     // Two-phased constructor.  

    static CNewClassTest* NewL();

     // Two-phased constructor.  

    static CNewClassTest* NewLC();

 

public:  

    // New functions  

    // Function for making the initial request  

    void StartL(TInt aState, TTimeIntervalMicroSeconds32 aDelay);

 

private:  

    // C++ constructor 

    CNewClassTest();

     // Second-phase constructor  

    void ConstructL();

 

private:  

    // From CActive  // Handle completion  

    void RunL();

    // How to cancel me  

    void DoCancel();

     // Override to handle leaves from RunL(). Default implementation causes  

    // the active scheduler to panic.  

    TInt RunError(TInt aError);

 

public:  

    enum TNewClassTestState  

    {   

        EUninitialized=12, // Uninitialized   

        EInitialized=22, // Initalized   

        EError=32 // Error condition  

    };

 

private:  

    TInt iState; // State of the active object  

    RTimer iTimer; // Provides async timing service

};

 

#endif // NEWCLASSTEST_H

 

/*  ============================================================================  

Name  : NewClassTest.cpp  Author   : Alex  Version  : 1.0  Copyright   : su-fun  Description : CNewClassTest implementation  ============================================================================  */

#include "NewClassTest.h"

 

CNewClassTest::CNewClassTest() :  CActive(EPriorityStandard) // Standard priority 


}

 

CNewClassTest* CNewClassTest::NewLC() 

{  

    CNewClassTest* self = new ( ELeave ) CNewClassTest();  

    CleanupStack::PushL(self);  

    self->ConstructL();  return self; 

}

 

CNewClassTest* CNewClassTest::NewL() 

{  

    CNewClassTest* self = CNewClassTest::NewLC();  

    CleanupStack::Pop(); // self;  

    return self; 

}

 

void CNewClassTest::ConstructL() 

{  

    User::LeaveIfError(iTimer.CreateLocal() ); // Initialize timer  

    CActiveScheduler::Add( this); // Add to scheduler 

}

 

CNewClassTest::~CNewClassTest() 

{  

    Cancel(); // Cancel any request, if outstanding  

    iTimer.Close(); // Destroy the RTimer object  

    // Delete instance variables if any 

}

 

void CNewClassTest::DoCancel() 

{  

    iTimer.Cancel(); 

}

 

void CNewClassTest::StartL(TInt aState, TTimeIntervalMicroSeconds32 aDelay) 

{  

    Cancel(); // Cancel any request, just to be sure  

    iState = aState;  

    iTimer.After(iStatus, aDelay); // Set for later  

    SetActive(); // Tell scheduler a request is active 

}

 

void CNewClassTest::RunL() 

{  

    if (iState == EUninitialized)  

    {   

        // older timer event, 当CActiveScheduler::Start()后,程序先到达这里   

        iState = 10;  

    }  

    else if(iState == EInitialized)  

    {   

        //// new timer event   

        iState = 201;   

        CActiveScheduler::Stop();  

    } 

}

 

TInt CNewClassTest::RunError(TInt aError) 

{  

    return aError; 

}

 

// 测试代码

// TInt ThreadEntry(TAny *arg), 用户线程的入口函数,省略了一些必要的初始化

 

TInt ThreadEntry(TAny *arg)

{

     CNewClassTest *obj1 = CNewClassTest::NewL();      

    CNewClassTest *obj2 = CNewClassTest::NewL();      

    obj-1>StartL(CNewClassTest::EUninitialized,TTimeIntervalMicroSeconds32(1000000));  //1(s)      

    User::After(5000000);  // sleep 5(s)      

    obj2->StartL(CNewClassTest::EInitialized,TTimeIntervalMicroSeconds32(20000));  //20(ms)      

    CActiveScheduler::Start();     

    delete obj1;     

    delete obj2;

}

 

        以上代码演示了如何灵活使用CActiveScheduler::Start(),至于具体的实现上,还需要调整一下,CActiveScheduler::Start()的必须还要同时启动一个超时定时器,当在设定的超时时间内没有任何异步时间完成,则在超时AO内停止活动规划器CActiveScheduler::Stop(),这样等待下一个循环到来再启动活动规划器。此时可继续执行被CActiveScheduler::Start()方法挂起的语句和方法。

 

总结:

1. 可以解决移植代码中出现的上述情况

2. 异步事件的完成检测有时延

3. 因为是异步事件,对于一定的时延,还是可以接受的 



本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/alex_hua/archive/2008/07/10/2633137.aspx

你可能感兴趣的:(symbian中活动对象的一些简单的使用 和 Symbian平台移植之——活动规划器CActiveScheduler的灵活应用)