【原创】 收藏
由于做工程的移植工作,需要移植代码到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. 因为是异步事件,对于一定的时延,还是可以接受的