Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1567570
  • 博文数量: 237
  • 博客积分: 5139
  • 博客等级: 大校
  • 技术积分: 2751
  • 用 户 组: 普通用户
  • 注册时间: 2008-11-18 14:48
文章分类

全部博文(237)

文章存档

2016年(1)

2012年(4)

2011年(120)

2010年(36)

2009年(64)

2008年(12)

分类: C/C++

2009-11-23 12:23:32

Symbian OS 中,针对有限的硬件资源,使用AO来实现多任务,与AO相比,多线程具有更高的运行期要求:线程上下文切换比同一线程中AO切换慢一个数量级;线程需要更 大空间的开销,通常线程要有4KB内核空间和8KB用户空间的程序栈,相比之下,AO只需C++对象的空间(通常小于1KB)。

使用线程和AO实现多任务的最大区别是它们被调用的方式不同。AO是协同式,而线程是抢占式。

有一种例外的情况是,考虑两个活动对象的情况,其一被赋予一个高优先级(响应UI),其二被赋予一个低优先级(但执行时间较长),这样就产生一个问 题,如果在响应低优先级AO的事件处理时,高优先级的AO事件完成,因为AO间不能进行抢占,这就阻滞了高优先级AO的事件处理函数,导致UI无法快速响 应。所以依然存在一些必须使用多线程的场合,例如执行一个无法被分割为简短片段的任务时,通过讲其实现在一个分离的线程中,从而可以异步运行该线程,而不 会影响到UI的响应。

总结:Symbian OS中,活动对象多任务是在一个线程中协同完成的,且无法为活动调度器所抢占,而线程则是由内核抢占调度的。

下面介绍关于线程的类RThread

在Symbian OS中,用于操作线程的类是RThread,一个RThead类型的对象代表一个线程的句柄(仅仅是个句柄,不要当成线程本身哦:-),一个 RThread对象可以用来创建或引用另一个线程,从而操纵它(例如挂起线程,恢复线程,使其发生严重错误或杀死线程),并且可以从中获取数据或向其输出 数据。RThread类定义在'e32std.h'中。

应该注意,模拟器以一个单独的进程运行,每个Symbian OS进程则以线程运行。但运行在手机硬件上的Symbian OS中,进程就是进程,线程就是线程~

RThread的基类是RHandleBase,该类封装了通用句柄的行为,并且在整个Symbian OS中都被用来表示另一个对象,通常是内核对象的句柄。RHandleBase封装了一个32位的对象句柄TInt iHandle。

使用RThread的默认构造函数可以获取代码当前所在线程的句柄,例如:
RHeap* myHeap = RThread().Heap(); // 当前线程堆的句柄
//.......
_LIT(KClangerPanic, "ClangerThread");
// 以KErrNotFound对当前线程抛出严重错误
RThread().Panic(KClangerPanic, KErrNotFound);

RThread()实际上产生的是一个伪句柄,它被置为常量KCurrentThreadHandle,该值被内核特别对待。如果要获得真正句柄(存在于线程句柄列表中),并要在进程中的不同线程之间传递,则需要使用RThread::Duplicate()来复制句柄。
RThread properhadle.Duplicate(RThread());

RThread提供了一些创建线程的Create()函数,它具有多种重载形式,当线程被创建的时候,它被赋予了一个惟一的TThreadId类型 的线程标识符,可以通过Id()返回,如果已知某线程的Id,则可以使用Open()来打开那个线程的一个句柄,另外一种方法是传递给Open()线程的 惟一名字。一旦获取了线程句柄,如果线程不被保护,则可以使用Rename()来更改线程的名称了,关于RThread的更多内容,请参阅SDK。

线程的优先级

在Symbian OS中,线程是被抢占式调度的,并且当前运行的线程是具有最高优先级的就绪线程。如果有两个或更多线程具有相同的优先级,那么它们将以轮转的方式划分时间片。
一个线程具有一个绝对的优先级,该值是由RThread::SetPriority()时被赋予线程的优先级计算出来的,是和其所在进程的优先级联合而得到的。TThreadPriority和TProcessPriority定义在'e32std.h'中
enum TProcessPriority
{
     EPriorityLow=150,
     EPriorityBackground=250,
     EPriorityForeground=350,
     EPriorityHigh=450,
     EPriorityWindowServer=650,
     EPriorityFileServer=750,
     EPriorityRealTimeServer=850,
     EPrioritySupervisor=950
};

enum TThreadPriority
{
     EPriorityNull=(-30),
     EPriorityMuchLess=(-20),
     EPriorityLess=(-10),
     EPriorityNormal=0,
     EPriorityMore=10,
     EPriorityMuchMore=20,
     EPriorityRealTime=30,
     EPriorityAbsoluteVeryLow=100,
     EPriorityAbsoluteLow=200,
     EPriorityAbsoluteBackground=300,
     EPriorityAbsoluteForeground=400,
     EPriorityAbsoluteHigh=500
};
线程的优先级有相对和绝对之分:
相对线程优先级 有:EPriorityMuchLess,EPriorityLess,EPriorityNormal,EPriorityMore,EPriorityMuchMore。 如果这些值被传递给SetPriority(),那么结果所得的线程绝对优先级是由相对线程优先级和进程优先级联合而得到的。例如,进程优先级为 EPriorityHigh,线程调用SetPriority()时传递EPriorityMuchLess,则线程的绝对优先级为 450-20=430。

其他的除了EPriorityRealTime之外的TThreadPriority值,都是绝对优先级。这些值使得线程优先级独立于进程优先级。使用EPriorityRealTime时,会将进程的优先级设置为EPriorityRealTimeServer。

所有线程缺省情况下都是以EPriorityNormal创建的,当进程被创建时,它开始被置于挂起状态,并且不会运行,直到调用Resume()在其句柄上被调用。RThread类不允许对除当前代码所在线程外的任何线程句柄调用SetPriority()。

停止一个运行的线程

运行着的线程可以通过RThread::Suspend()来将其从调度器的就绪队列中移除,但该线程仍然存在着,并且通过Resume()就可以调度它,从而可以继续运行。

一个线程可以通过Kill()或Terminate()而永远将其中止,如果进程的主线程被中止了,那么这个进程也就被中止了。调用这些函数时,需 要传递给他们一个Kill的原因TInt aReason。通过对已中止线程的RThread句柄调用ExitType(),ExitReason()以及ExitCategory()来判断线程 是通过什么方式中止的,并可以了解退出的原因。退出类型表明是否调用了Kill(),Terminate()或Panic(),或者表明线程是否仍在运 行。退出原因是指传递给Kill()或Terminate()的参数值,或者是发生panic的原因。分类则是一个含有严重错误分类的描述符,诸 如"Kill"或"Terminate"。如果线程仍在运行,退出原因就是0,而退出分类则是一个空字符串。

RMessagePtr具有和RThread一致的Kill(),Terminate()和Panic()方法,这些方法允许一个服务器中止客户线程。

当线程死亡时,还可以接收到通知。以一个TRequestStatus引用为参数,对一个有效的线程句柄调用RThread::Logon(),就 可以提交一个获取线程中止通知的请求。该请求会在线程中止时完成,并得到一个线程中止的值,或者如果通过调用 RThread::LogonCancel()撤销通知请求,则会获得KErrCancel值。

进程类RProcess

RProcess类用来获取一个运行进程的句柄,在'e32std.h'中定义。
可以使用默认构造函数可以创建一个当前进程的句柄,用Create()函数可以创建一个新的具有名字的进程,而用Open()函数可以通过进程名或进程标 号(TProcessId)打开一个进程的句柄。RProcess中没有Suspend()函数,因为进程是不可被调度的。线程是最基本的执行单元,运行 于进程的保护地址空间。

Symbian OS中最基本的进程--内核服务器进程。它包含了两个运行于超级用户特权级别上的线程:
1. 内核服务器线程
这是系统的第一个线程,并且它在所有线程中具有最高的优先级。它实现了所有要在内核堆内存上进行分配或回收的内核函数,并且也负责管理硬件资源。
2.“空(NULL)”或“空闲(Idle)”线程
该线程具有系统中最低优先级,而且只有在没有其他线程处于准备运行状态时,该线程才会运行。该线程会通过回调函数关闭部分硬件,从而将处理器切换到空闲模式来节约能源。

其他线程都是用户线程,它们运行在非特权状态下,用户线程可以通过用户库(EUser.dll)中的API来访问内核服务,诸如其他线程或进程。当 一个用户线程请求一个内核服务时,EUser或者切换到内核状态下运行,即在当前运行的线程上下文中执行具有内核特权的代码,或者通过一个调用转入内核服 务器进程中进行。

阅读(1240) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~