Symbian也是多任务操作系统,当然也要用进程、线程完成多任务处理。进程是程序的运行实例,有自己独立的数据空间。线程是进程的执行单元,一个进程至少有一个主线程。多线程可以并发运行采用抢占式完成多任务处理。但是Symbian下不提倡使用多线程,因为Symbian系统是通过客户端/服务器结构来提供对线程资源的访问,这就意味着访问线程需要与内核的服务器程序不断地进行通信,效率低。
在单线程内,配合使用活动对象+异步函数,完全可以模拟多线程并行运行。不同的是,这是一种非抢占式并行运行,即当前活动对象结束之前,其它活动对象不能运行。 异步函数在执行后立即返回,继续执行它下面的代码。异步操作有后台继续执行,结束后通过信号量表示异步操作结束。同步函数必须函数内所有操作全部执行结束后才能返回,执行下面的代码,否则就阻塞在那里。很显然,实现多任务并行运行必须使用异步函数。
活动对象是CActive的派生类,设立它的作用就是为了提供一个专门用来调用异步函数的类。因为这个类中专门设有回调函数,使异步函数结束后,能利用这个回调函数进行尾处理。这个函数就是RunL()。在活动对象外面使用异步函数,只能截获信号量,不能直接进入某个回调函数。
异步函数结束后,是如何进入到正确的回调函数中的呢?系统运行着一个活动调度器(CActiveSchedule),它能截获异步函数结束后发出的信号量,并根据这个信号量,调用相应的RunL()。问题是如果CActiveSchedule截获了这个信号,但却找不到该调哪个活动对象的RunL()怎么办?这时CActiveSchedule会抛出异常,这种状态叫信号游离,这种状况经常发生,所以使用活动对象应该避免这种情况发生。
哪些情况会产生游离信号?理解这个问题首先要了解CActiveSchedule如何判断这个信号是不是游离信号。CActiveSchedule判断游离信号的条件是
for(I=0;I<NUMBERS_OF_ACTIVE_OBJECT;I++)
{
IF(ACTIVE_OBJECTS[I].iActive==ETrue&&ACTIVE_OBJECTS[I].iStatus!=KRequestPending)
{
//由此可见,规则有二
//规则1 根本就没有这个活动对象
//规则2 活动对象不是“活”的 ACTIVE_OBJECTS[I].RunL();
}
}
所以有如下情况可能会导致出现游离信号出现
1.没有调用CActiveSchedule::Add(this);把活动对象加到活动调度器中。
2.没有调用SetActive把活动对象激活。破坏规则(2)
3.在活动对象外调用异步函数后,没有用User::WaitForRequest()截获异步函数完成信号量。信号量进入循环却找不到活动对象,破坏规则1。
4.同时一个活动对象中同时调用两个异步函数。如:InvokeAsyncFunc1();SetActice();InvokeAsyncFunc2();SetActive();第一个异步函数结束后,执行完回调函数RunL()后,会把iActive置为EFalse,这时第二异步函数的结束信号进入时,却发现活动对象不是“活”的,破坏规则2。所以在一个活动对象不能同时调用多个异步函数。