技术开发 频道

Symbian开发不可忽视的多线程

  【IT168技术】做过开发的朋友都知道,symbian操作系统中对多任务的实现更提倡使用活动对象,用以避免线程间上下文之间切换带来的额外开销,但多线程也是非常有用的技术,当移植程序、后台大量复杂运算或多媒体编程时,threads都是必不可少的。symbian中的thread编程和一般的多线程编程差不多,下面就来看看具体文档中是如何描述的。

  《Symbian OS:线程编程》是一本很不错的书,对于线程的开发讲解的挺详细,借此推荐一下。

  Symbian操作系统中的线程和进程的相关介绍:

  在Symbian操作系统中,每个进程都有一个或多个线程。线程是执行的基本单位。一个进程的主线程是在进程启动时生成的。

  Symbian属于抢占式多任务操作系统,这意味着每个线程都有自己的执行时间,直到系统将CPU使用权给予其他线程。当系统调度时,具有最高优先权的线程将首先获得执行。

  进程边界是受内存保护的。所有的用户进程都有自己的内存地址空间,同一进程中的所有线程共享这一空间,用户进程不能直接访问其他进程的地址空间。

  每个线程都有它自己的stack和heap,这里heap可以是私有的,也可以被其他线程共享。应用程序框架生成并安装了一个active scheduler,并且为主线程准备了清除栈。如果没有使用框架(如编写exe程序)那就要手动生成这些了

  Symbian操作系统专为单线程应用优化,因此强烈推荐使用“活动对象”代替多线程。

  一、使用单线程的优点有以下几点:

  1.在每个线程都有自己的stack空间时,使用单线程可以减少内存耗费。

  2.在线程间切换上下文要比切换活动对象(通过active scheduler)慢得多。

  3.不需要处理互斥现象,这减少了程序的负担,简化了代码,减少了错误发生的几率。

  4.一些资源只能为主线程所用,因此它们并不是线程安全的,如动态数组。

  二、使用多线程的优点:

  有时为了保证所执行的任务的持续性,如播放声音时,我们可以将其归在一个单独的线程中处理。

  将复杂的多线程或长时间运行程序移植到Symbian上,如果不使用多线程处理,可能会比较难也更耗时间。例如,我曾綺将一个棋类程序移植到symbian上,里面复杂的递归运算使我不得不使用多线程,这样的情况下,你是很难将时间有序的分化开来,使用活动对象的

  线程的基本使用方法如下:

  RThread提供了线程的各项功能。线程是为内核所拥有的对象,RThread对象封装了这些对象的句柄。

  一、生成一个新线程

  新的线程可以通过构造一个RThread对象,并调用它的Create()函数生成。如:

  Code:

  1: TInt threadFunction(TAny *aPtr)

  2: RThread thread;

  3 thread.Create(KThreadName, threadFunction, 4096, KMinHeapSize, 256*KMinHeapSize, &iParameter);

  4: thread.Resume();

        5.thread.Kill();

  二、线程状态

  一个线程的最重要的状态为运行、准备、等待和暂停。在生成后,线程首先处于暂停状态,你可以调用Resume()函数来启动它的运行。一个线程也可以通过调用Suspend()来进入中断状态。

  线程一般通过Kill(TInt aReason)来结束,Terminate()与其相似。如果一个进程的主线程结束,则该进程与所属所有线程都将结束。

  一种非正常关闭线程的方式就是调用Panic(const TDesC& aCategory, TInt aReason)来中断执行。

  如何获得中断线程的信息呢,我们可通过ExitType(),ExitReason()以及ExitCategory()方法来获得。

  线程可以在中断时发出请求,我们通过调用异步方法Logon()来完成此任务。返回值在aStatus中。LogonCancel()可以取消前次请求。

  void Logon(TRequestStatus& aStatus) const;

  TInt LogonCancel(TRequestStatus& aStatus) const;

  我们可以通过SetProtected(ETrue)方法将线程保护起来,也可以通过SetProtected(EFalse)来取消保护。在保护时,另一个线程是无法中断、结束、异常中断或设置该线程的优先级的。Protected()方法可以返回该线程的保护状态。

  三、访问线程及进程

  我们可以通过构造一个RThread对象来访问当前线程。Id()方法可以返回改线程的ID。AVA手机网[www.cnj

  拥有此线程的进程可以通过访问RThread的Process(RProcess& aProcess)方法来获得。这里传入的参数应该是一个RProcess对象。

  其他线程可以通过Open()方法来访问。我们通过传递TThreadId、线程名称或TFindThread对象来打开线程。

  TInt Open(const TDesC& aFullName, TOwnerType aType=EOwnerProcess);

  TInt Open(TThreadId aID, TOwnerType aType=EOwnerProcess);

  TInt Open(const TFindThread& aFind, TOwnerType aType=EOwnerProcess);

  Code:

  1: // * as a wildcard for the name search

  2: _LIT(KFindAll, “*”);

  3: // default RThread object, has a handle of the current thread

  4: RThread thread;

  5: TFullName fullName;

  6: TFindThread finder(KFindAll);

  7: while (finder.Next(fullName) == KErrNone)

  四、线程优先级

  线程可以被赋予一个绝对或相对的优先级。绝对优先级定义了这个线程的总体优先级,不需要考虑其拥有者进程的优先级了。而赋予相对优先级时则将此线称定义为拥有者进程的优先级加上该相对优先级后的结果。

  下面粗体标示的优先级值可以由用户代码设置:

  Code:

  enum TProcessPriority;

  enum TThreadPriority;

  上面枚举出来的值中绝对优先级值为:

  EPriorityAbsoluteVeryLow, EPriorityAbsoluteLow, EPriorityAbsoluteBackground, EPriorityAbsoluteForeground, EPriorityAbsoluteHigh.

  相对优先级值为:

  EPriorityMuchLess, EPriorityLess, EPriorityNormal, EPriorityMore, EPriorityMuchMore.

  EPriorityNull是一个特殊值,它定义了最低的级别,Kernel idel thread使用的就是它*_*

  EPriorityRealTime定义了除核心服务线程优先级外最高的总体优先级。

  RThread中的Priority()方法返回了一个线程的优先级(按以上描述值)。我们也可以通过SetPriority(TThreadPrioriy aPriority)方法来修改优先级。

  ProcessPriority()方法返回了拥有该线程之进程的优先级(按TProcessPriority描述值)。我们也可以通过SetProcessPriority(TProcessPriority)方法来修改该进程的优先级。

  五、异常处理

  每个线程都有自己的异常处理模块。当线程发生异常时会调用异常处理模块。异常处理模块的訽型为:

  typedef void TExceptionHandler(TExcType);

  RThread包含了下列异常处理相关的方法:

  TExceptionHandler* ExceptionHandler()

  返回该线程当前异常处理模块的地址。

  TInt SetExceptionHandler(TExceptionHandler* aHandler, TUint32 aMask);

  定义了该线程新的异常处理模块的地址,以及它所处理异常的类别。

  void ModifyExceptionMask(TUint32 aClearMask, TUint32 aSetMask)

  修改异常处理模块所定之异常类别,aClearMask参数定义了不再为异常处理模块所处理的类别,而aSetMask则定义了新的处理类别。

  TInt RaiseException(TExcType aType);

  引发线程上指定类型的异常,这时异常处理模块将被启动执行(发生在调用之后)。

  TBool IsExceptionHandled(TExcType aType);

  检查线程的异常处理模块是否捕捉到aType类型的异常。

  (1)异常类别及类型

  异常类型是一组针对单个异常的类型识别,主要用在异常发生时。

  异常类别则代表一组异常形式。

  异常类别的一个集是由一个或多个异常类别通过OR形式组合成的,如KExceptionInteger|KExceptionDebug,这些值用来设置及修改异常处理模块所处理的类别。

  下面列示了所有的类型及类别。

  异常类别 异常类型

  KExceptionInterrupt ->EExcGeneral, EExcUserInterrupt

  KExceptionInteger ->EExcIntegerDivideByZero, EExcIntegerOverflow

  KExceptionDebug->EExcSingleStep, EExcBreakPoint

  KExceptionFault ->EExcBoundsCheck, EExcInvalidOpCode, EExcDoubleFault, EExcStackFault, EExcAccessViolation, EExcPrivInstruction, EExcAlignment, EExcPageFault

  KExceptionFpe ->EExcFloatDenormal, EExcFloatDivideByZero, EExcFloatIndexactResult, EExcFloatInvalidOperation, EExcFloatOverflow, EExcFloatStackCheck, EExcFloatUnderflow

  KExceptionAbort ->EExcAbort

  KExceptionKill->EExcKill

0
相关文章