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()
- {
-
- iTimer.After(iStatus, 10000 * 100 * mTime);
-
- SetActive();
- }
- void TimeCount::ConstructL()
- {
-
- iTimeCount = 0;
- User::LeaveIfError(iTimer.CreateLocal());
- }
- void TimeCount::RunL()
- {
-
- 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的处理函数.
From:
http://blog.csdn.net/wistaria2002/archive/2008/07/23/2696920.aspx
(wistaria2002) |