异步机制, 活动对象,CTime,RTime
1. 异步事件
Symbian OS 中异步函数最显著的特征是拥有TRequestStatus& 类型的参数.
异步函数本身不提供服务,提供服务的是其他程序,所谓的服务提供者.
基本原理: 应该程序调用异步函数时指向服务提供者发送一个请求,发送完毕后函数调用返回,应用程序继续执行的
同时,服务提供者会处理该请求,处理完毕后服务器提供者向应用程序发送一个异步事件,接收到事件后应用程序才能
知道请求的服务是否完成.
Symbain OS 推荐的处理异步事件的方法有两种,:
第一种是使用信号量机制User::WaitForRequest()静态函数等待异步服务器完成.
......
TRequestStatus status;
AsyncFunction(status);
User::WaitForRequest(status);//等待异步服务完成
......
第二种是使用活动对象机制,效率高,也不会阻塞应用程序,下面我们学习...
2. 活动对象机制
活动对象机制包括两个比较重要的概念:活动调度器和活动对象.
---------------------------------------基础部分-----------------------------------------------------
-
(1) 活动调度器
活动调度器维护着一个优先级队列,该队列存放着应用程序中所有活动对象.应用程序可以调用CActiveSchcdulc
r::Add()
静态函数将新建的活动对象添加到这个队列中.
主要作用是: 分发和接收异步事件 。应用程序的活动调度器最先接收到异步事件,随后他会从队列中选出处于
活动状态而优先级最高的活动对象,先将它的状态置成非活动,然后将事件分发给它处理.
CActiveSchcdulcr : public CBase
{
public:
...
static void Add(CActive* anActive);
...
private:
...
TPriQue<CActive> iActiveQ;//活动对象队列
}
(2) 活动对象
活动对象是CActive类子类的对象.
class CActive : public CBase
{
...
public:
~CActive();
void Cancel();
void Deque();
...
inline TBool IsActive() const;
...
protected:
CActive(TInt aPriority);
...
virtual void DoCancel() = 0; //取消异步请求
virtual void RunL() = 0; //活动对象的事件处理函数
virtual TInt RunEror(TInt aError);
public:
TRequestStatus iStatus; //状态标记,指示异步事件完成状态
TBool iActive;//活动标记,对象是否活动状态,是否等待异步事件
}
主要作用: 发送(取消)异步事件,处理异步事件,一个活动对象一次只能处理一个异步事件.
--------------------------------实践部分----------------------------------------------
我们分为两步分讨论: 活动对象和运行机制
(1) 实现活动对象
//CMyActive.h
...
class CMyActive : public CActive
{
public://构造函数和析构函数
static CMyActive* NewL();
void ConstructL();
~CMyActive();
CMyActive();
public: //新定义的函数
void IssueRequest(); // 发送异步请求函数
public: //继承CActive类的函数
void DoCancel(); //取消请求函数
void RunL();//事件处理函数
TInt RunError(TInt aError);//处理 RunL()抛出的异常
...
}
//CMyActive.cpp
/*
活动对象的优先级
EPriorityIdle 用于在后台利用系统空闲时间处理不太紧迫的批量任务
EPriorityLow 低于标准优先级
EPriorityStandard 用于处理一般的前台任务
EPriorityUserInput 用于处理用户输入
EPriorityHigh 用于处理更高优先级的任务,如屏幕刷新
*/
//指定活动对象的优先级
CMyActive :: CMyActive():CActive(CActive::EPriorityStandard)
{
......
}
//将活动对象添加到活动调度器
void CMyActive :: ConstructL()
{
CMyActiveScheduler :: Add(this);
}
//实现异步请求
void CMyActive :: IssueRequest()
{
AsyncFunction(iStatus);
SetActive();
}
//取消异步事件
void CMyActive :: DoCnacel()
{
......
}
// 实现异步事件处理
void CMyActive::RunL()
{
if(iStatus.Int() == KErrNone)
{
//请求的服务成功完成,加入处理程序
}
else
{
//加入错误处理代码
}
}
//处理异常处理
void CMyActive ::RunError()
{
...
}
//实现析构函数
void CMyActive :: ~CMyActive()
{
Cancel();
}
(2) 运行机制
活动对象 ----> 服务提供者 ----> 活动调度器 -----> 活动对象
-----> 活动对象
-----> 活动对象
如上图
第一步: 活动对象调用IssueRequest()向服务提供者发送异步请求.调用之后活动对象的状态标记iStatus
成员被异步函数AsyncFunction()设置成KRequestPeding,活动标记iActive被SetActive()函数设置成ETrue.IssueRequest()
调用返回后应用程序照常执行, 同时服务器调用者处理收到请求.
第二步: 服务提供者成功处理完请求后将活动对象状态标记iStatus设置成KErrNone(不成功设置为错误代码),然后向
应用程序发送一个异步事件.
第三步: 活动调度器接收到异步事件后在他的优先级队列中寻找iActive值是ETrue值,iStatus值是KRequestPeding
的活动对象.从中选择一个优先级最高的,将他iActive设置成EFalse,然后调用它的RunL().
-----------------------------------------------------------------------------------------------------------
定时器服务
1. 同步定时器服务
----------------------------------
User :: After(1000000)//延时1秒钟
----------------------------------
...
TTime time;
time.HomeTime();//获取当期那系统的时间
time.TTimeIntervalMInutes(1); //指定目标时间(比当前系统时间晚1分钟)
User::At(time);//延迟1分钟
2. 异步定时器服务
解析:通过RTimer类提供异步定时器服务,通过该类向系统发送异步请求,是系统满足某些条件时向应用程序发送异步事件,
请求包括:
* 在指定的时间间隔之后发送一个异步事件
* 在指定的时间发送一个异步事件
void At(TRequestStatus& aStatus, const TTimer& aTime);
* 在一秒中固定的时间段发送一个异步事件
void Lock(TRequestStatus& aStatus, TTimerLockSpec aLock);
* 在指定的时间间隔内没有用户活动(例如按键)时发送一个异步事件.
void Inactivity(TRequestStatus& aStatus, TTimeIntervalSeconds aSeconds);
RTimer类
...
RTimer timer; //此时无定时器与timer相关联
User::LeaveIfError(timer.CreateLoacal());//创建定时器
timer.close();
//1秒后iTimer所属的活动对象调度运行
...
iTimer.After(iStatus, 1000000); // iTimer是RTimer类的对象
SetActive();
...
转换成同步操作
TRequestStatus status = KRequestPeding;
timer.After(status, 1000000);//发送异步请求
User::WaitForRequest(status);//同步等待请求完成
----------------------------------------------------
//计算运行时间
...
TInt period;
User::LeaveIfError(IIalData::ESystemTickPeriod, period);
TUint start = User::TickCount();//获取起始时刻的滴答数
//执行一段代码
TUint end = User::TickCount();//获取终止时刻的滴答数
TInt64 runtime = end -start;
runtime *= period;//计算运行时间
...
-----------------------------------------------------
CTimer类
简单的实现过程:
CMyTimer :: CMyTimer():CTimer(EPriorityStandard)
{...}
void CMyTimer::ConstrutL();
{
CTimer :: ConstrutL();//创建定时器对象
CActiveScheduler::Add(this);
}
void CMyTimer :: Start(const TTime& aTime)
{
Cancel(); //防止重复发送请求
TTime now;
now.HomeTime();
iTargetTime = now.Int64() + aTime.Int64();//记录时间
After(KInterval);//发送请求
}
void CMyTimer :: RunL()
{
TTime now;
now.HomeTime();
TTime time = iTargetTime.Int64() - now.Int64();//计算剩余时间
if(time.Int64() > 0)
{
After(KInterval);//如果没有倒数到0继续请求定时器事件
}
else
{
time = 0;
}
iObserver.OnTimerL(time);
}
以上是简单的分析,了解一些API函数和概念,在手机病毒分析中参考.