Symbian S60的开发多以活动对象CActive为主,活动调度器CActiveSchedule负责调度各种CActive的RunL方法进行执行。其实可以抽象的将不同活动对象的RunL方法相当于一个可执行的线程。其实整个执行一直都是在不同的RunL方法中进行跳转。请求异步调用只不过是激活相应活动的RunL方法变成可调度状态。
其实个人觉得这种编程模型虽然省去了多线程模型可能会碰到的同步问题,因为始终在一个线程中。但是同样也不允许调用同步调用,任何阻塞线程的方法会其他活动对象的功能得不到执行。然后编程合作时你会看到通知者满天飞,模块耦合下高,栈的迭代层次巨大。
位同步是一种不太常用的技巧,可以模拟同步等待,但是不会导致其他活动对象停止调度。其用到了CActiveScheduleWait这个类。
伪同步常用的写法为:
Class CMyActive: public CActive
{
Public:
….
Void Request();
Private:
Void RunL();
TInt RunError(Tint aErr);
Private:
CActiceScheduleWait iWait;
}
Void CMyActive::Request
{
ASynacRequest(iStatus);
SetActive();
iWait.Start();
}
Void RunL()
{
DoSomethingL();
iWait.AsyncStop();
}
Tint RunError(Tint err)
{
iWait.AsyncStrop();
Return KErrNone;
}
客户端调用
...
CMyActive* iActive = CMyActive::NewL();
...
iActive->Request(); //这个方法并不会立即返回,也不会阻止其他活动对象的调度
//当这个方法返回是,说明这个请求已经完成了
DoSomething();
.....
上述描述就是Symbian中的伪同步机制的基本引用,比方说在解码图像时,可能不希望解码完成后利用通知者通知,就可以利用这种模型.
伪同步揭秘
伪同步并不会一定造成线程的阻塞,如果有信号量,是可以继续调度的,网上有些人瞎说的,简直误人,如果阻塞线程就会导致其他的活动对象得不到相应了。其真实的面貌是当CActiveSchedulerWait调用Start方法后,会调用CActiveScheduler的Start带有层次参数方法,重新开始新一轮的调度.所以这个时候调用堆栈应该是这样的:
CActiveScheduler::Start-->CAcitive::RunL-->CMyActive::Request()-->CActiveScheduler::Start(&Loop).这里的iLoop实际上是全局的一个链表形式的堆栈,记载了调度的层次和每一次的调度对象的信息.调用CActiveScheduler的Halt方法会去掉最上层的TOOP的Owner信息,导致Start方法立即返回。而CActiveSchedulerWait的方法只会去掉其所属层次owner信息,上层的Start方法不会立即返回。这在多重嵌套中有着重要的意义。也就是说,如果采用CActiveSchedulerWait方法返回,则最后发出的伪同步请求一定得到最新的响应并返回。而采用Halt方法则会导致后发出请求得不到相应,属于强制的退出当前调度层次。
所以位同步请求实际上是通过增加调度层次来实现的,可利用的空间不大。在模式对话框中用途会比较多吧。