- 浏览: 23771 次
- 性别:
- 来自: 福建
-
最近访客 更多访客>>
最新评论
-
zhiqi0158:
如果我想找application uid呢,在哪里可以查到?
...
How to launch an application with its UID -
iamsk:
还没用过s系统的手机呢,过两天准备买个5800,听说可以装py ...
S60 相对于S40 不够人性化的地方
转载自:杨芹勍的博客 http://www.cnblogs.com/felixYeou/
第1节 理解活动对象
Symbian OS中的活动对象的使用无疑是最基础的、最频繁的、最重要的。什么是活动对象呢?
大家学习一个新的事物时,总是会将这个新的事物与自己认知的事物相比较,从而达到快速学习的目的。我开始学习Symbian的时候,我查看很多Symbian书籍、网上很多 Symbian教程都将活动对象与多线程联系到一起,我也总是会把活动对象想象成一个线程。然而,经过了更深入的接触,我发现并不像我想象的那样。
现在,我在此向你保证:活动对象和多线程没有任何关系!不要拿平时做多线程的思想去理解活动对象!
活动对象可以按照以下步骤这么理解:
Symbian OS中提供了很多异步函数,这些异步函数大多部分都是基于“服务器-客户端”架构的。这里与win32 api中的函数有很大的不同。如:
win32中,CSocket::Receive(是recv而不是WSARecv)为同步函数,线程阻塞在Receive处,直到套接字接收到了网络流才返回。
Symbian OS也有类似的函数,RSocket::Receive,但是此函数是一个异步函数,线程不会阻塞在Receive处而会继续执行。
如何区分Symbian中的函数哪些是同步的哪些是异步的?
很简单:看函数内是否包含类型为TRequestStatus的形参,如果有则函数为异步函数。如RSocket::Receive的函数原型为:
IMPORT_C void Recv(TDes8 &aDesc, TUint flags, TRequestStatus &aStatus)
参数aStatus为一个状态位,初始值为ERequestPending(值为1),它意味着用户请求的操作是否执行完毕。如:我们调用异步函数 RSocket::Receive请求接收网络流,Receive函数会直接返回。当“接收”网络流的过程完毕后,aStatus会变为EActive,所以我们只要监视aStatus是否不为ERequestPending就可以知道“接收”是否完成了。
我们可以使用以下伪代码完成以上所述操作:
TRequestStatus status(KRequestPending); RSocket::Receive(aDesc, flags, status); for (;;) { if (status != KRequestPending) break; } // 此处我们已经通过RSocket::Receive完成了类似CSocket::Receive的同步的工作
Symbian OS不建议我们使用以上方法,它建议我们使用异步方法,而不要使用我们这种方法去强制同步,活动对象就是帮我们做这件事情。活动对象体系帮我们监视 aStatus的值,只要aStatus != ERequestPending,他就会以事件的方式通知我们,告诉我们“Socket已经接收完毕,你可以去取数据了!”,活动对象就是干这事的。
总结一下:系统中有一个“活动调度器”,我们建立一个“活动对象ao1”,将该对象与某个系统中的异步函数绑定,然后将该活动对象注册到“活动调度器” 中,“活动调度器”会等待异步函数返回的“完成”消息。收到完成消息后,调度器遍历所注册的活动对象,如果发现status != KRequestPending则找到该status对应的“活动对象ao1”,调用其中的RunL方法,以事件的方式告知我们异步函数已经执行完成。
在下一节我会介绍如何使用活动对象。
第2节 使用活动对象
在上一节里我们已经大致了解了活动对象的基本概念,要使用活动对象机制,需要用到活动对象、活动调度器、异步函数。我们想使用异步函数,要按照应用程序->活动对象->活动调度器->异步函数
的流程来使用。接下来我们开始进入实战,使用活动对象。
一、创建活动调度器
我们知道,活动调度器是应用程序和异步函数之间的桥梁,应用程序使用活动对象通过活动调度器去截获异步函数的返回“完成”消息,并以事件的方式通知应用程序。
使用Carbide C++ 1.3,通过模板向导生成的控制台程序自动为我们生成了创建活动调度器的代码:
CActiveScheduler* scheduler = new (ELeave) CActiveScheduler(); CActiveScheduler::Install(scheduler);
CActiveScheduler::Install()方法调用以后,内部代码就会将scheduler指针赋值给CActiveScheduler类内部的静态指针,后面的代码就可以方便的使用CActiveScheduler类的静态方法,如:
IMPORT_C static void Add(CActive* aActive); IMPORT_C static void Start(); IMPORT_C static void Stop();
Add()方法:将活动对象加入活动调度器中注册,以备使用
Start()方法:启动活动调度器,活动调度器将开始循环等待异步函数返回的通知消息
Stop()方法:停止活动调度器
二、创建活动对象
1、我们创建的活动对象必须派生自CActive类,CActive类已经为我们准备好了iStatus成员变量:
public: TRequestStatus iStatus; private: TBool iActive;
另外一个成员变量iActive起着标识作用,证明该活动对象已经请求了异步函数,如:
RTimer::After(iStatus, 1000000); SetActive();
SetActive()方法为基类CActive的方法,其实就是将iActive = ETrue;,用来标识活动对象已经调用了异步函数。所以,我们只要调用了异步函数,在调用异步函数的代码后面应该紧挨着调用SetActive()方法的代码。
2、有两个纯虚方法必须继承:
virtual void DoCancel() =0; virtual void RunL() =0;
RunL方法:活动调度器接收到异步函数返回的“完成”消息后,遍历在其注册的所有活动对象,如果活动对象的iActive = ETrue且iStatus != KRequestPending则调用活动对象的RunL方法,并将iActive设置成EFalse,以防下次轮询时仍然调用此活动对象。
在这里“RunL”这个名字会让很多人产生歧义,我刚开始接触的时候总以为和J2me中的Runnable接口的run方法差不多。其实在这里把“RunL”改为“NotifyRequestCompleteL”更贴切些。
再次声明一下,调用异步函数时,参数TRequestStatus& status都是以引用的方式传递的
,如:
IMPORT_C void After(TRequestStatus &aStatus, TTimeIntervalMicroSeconds32 anInterval);
所以异步函数内部可以改变status的实参,也就是改变活动对象的类成员iStatus。
DoCancel()方法:基类CActive中有取消异步函数的方法Cancel(),调用Cancel()后,活动对象会通过DoCancel() 方法通知应用程序做取消方法的后期工作,如删除对象及回收指针等。注意:在应用程序中如果想终止活动对象,要使用Cancel()方法调用而不是 DoCancel()方法。
3、活动对象的带优先级的构造函数:
基类CActive的构造函数原型如下:
protected: IMPORT_C CActive(TInt aPriority);
此处将传入一个优先级枚举值,枚举值内容如下:
/** Defines standard priorities for active objects. */ enum TPriority { /** A low priority, useful for active objects representing background processing. */ EPriorityIdle=-100, /** A priority higher than EPriorityIdle but lower than EPriorityStandard. */ EPriorityLow=-20, /** Most active objects will have this priority. */ EPriorityStandard=0, /** A priority higher than EPriorityStandard; useful for active objects handling user input. */ EPriorityUserInput=10, /** A priority higher than EPriorityUserInput. */ EPriorityHigh=20, };
当调用CActiveScheduler::Add方法注册活动对象时,活动调度器会按照活动对象的优先级进行排序,插入或添加到活动对象集合中。在此会起到如下作用:当多个异步函数消息同时返回时(多个iStatus同时不为KRequestPending),活动对象调度器轮训集合的时候总是会先找到优先级高的活动对象并调用其RunL方法。
但是在通常情况下,我们会在构造函数传入EPriorityStandard
。
三、活动调度器Start方法的伪代码
通过以上两点分析,我们完全可以模拟出CActiveScheduler::Start方法:
void CActiveScheduler::Start() { for (;;) { // 挂起线程直到异步函数消息返回 // 注:活动调度器和应用程序不在一个线程,所以应用程序不会阻塞 User::WaitForAnyRequest(); // 如果异步函数和主程序在不同的线程则RThread::WaitForAnyRequest(); // 当消息返回的时候线程会苏醒 // 以优先级降序的方式检测调度器集合中每个活动对象 for (;;) { // 调用第一个已完成且iActive == ETrue的活动对象事件处理函数 if (activeObject->IsActive() && activeObject->iStatus != KRequestPending) { // 找到一个已准备好处理事件的活动对象 // 重置iActive状态以表明其不再是活动状态了 activeObject->iActive = EFalse; // 在TRAP中调用活动对象的事件处理函数 TRAPD(err, activeObject->RunL()) ; if (err != KErrNone) { // 如果异常则调用活动对象的RunError方法 err = activeObject->RunError(); if (err != KErrNone) { Error(err); } } break; } } } }
四、使用活动对象的例子
点击此处下载源代码
此例子将启动一个控制台程序,并使用异步服务类RTimer定时器,每隔一秒在屏幕上显示累加的数字,效果如下:
五、小结
在这一节中,我们基本了解了活动调度器、活动对象的工作机制及工作流程,在下一节里,我们将深入活动对象的内部,了解其工作原理,进一步加深对活动对象的理解。
六、参考文献
1. Symbian OS Explained Effective C++ Programming for Smartphones
第3节 活动对象的工作原理。
在上一节里我们已经知道如何创建和使用活动对象,大家对活动对象的创建、使用都有了一定的了解。在这一节里我将深入活动对象机制,分为“活动对象的工作流程”、“信号迷失错误”两个部分,为大家剖析活动对象的工作原理。
一、活动对象工作流程
首先我们用时序图来说明一下应用程序、活动对象、活动调度器及异步函数服务器之间创建及调用的流程:
下面我们针对每一个步骤结合代码(点击此处下载代码
)进行说明:
1、创建并安装活动调度器:
CActiveScheduler* scheduler = new (ELeave) CActiveScheduler(); CleanupStack::PushL(scheduler); CActiveScheduler::Install(scheduler);
如果创建了一个基于GUI应用程序框架的应用程序,框架已经为我们创建并且安装了活动调度器,我们可以直接使用CActiveScheduler的一系列方法。
2、创建活动对象
iMyAO = CMyActiveObject::NewL(*console);
此处创建的CMyActiveObject类是继承自CActive类的活动对象。
3、将活动对象添加到活动调度器中
void CMyActiveObject::ConstructL() { .... CActiveScheduler::Add( this); // Add to scheduler }
可以看到,活动对象在通过“二阶段构造”创建时就已经将自己的指针添加到了活动调度器中
。
4、StartL
StartL为应用程序请求活动对象调用异步函数的方法,此处用户可以根据自身需求对此方法重新命名:
void CMyActiveObject::StartL(TTimeIntervalMicroSeconds32 aDelay) { Cancel(); // 取消异步函数请求 iStatus = KRequestPending; iTimer.After(iStatus, aDelay); // 在此处调用异步函数 SetActive(); // 将成员变量iActive = ETrue }
因为不能保证用户在等待异步函数调用完毕返回的时候不重新调用StartL方法,所以在StartL方法的入口点首先调用Cancel()方法取消异步请求,否则可能会发生臭名远扬的“信号迷失”错误。
5、iStatus = KRequestPending
在以上代码StartL方法中,异步函数调用之前,首先要将iStatus设置为KRequestPending以便活动调度器遍历时匹配。
6、请求异步函数并发送iStatus
在StartL方法中,iTimer.After(iStatus, aDelay);这行代码传递了成员变量的引用并调用了异步函数iTimer.After。
7、SetActive
调用基类CActive的SetActive方法,方法内部将iActive设置成ETrue,以便活动调度器遍历时匹配。
8、启动活动调度器
CActiveScheduler::Start();
10、查找对应的活动对象
我们在上一节已经通过分析并还原了CActiveScheduler::Start()方法的伪代码,此代码块在另外一个线程遍历所有向调度器注册的活动对象,查看对象的iStatus不为KRequestPending且iActive为ETrue。因为异步函数服务器完成了请求的工作以后,会改变 iStatus的实参,使其不等于KRequestPending,再加上活动对象在调用完异步函数返回后马上改变了iActive值为ETrue,所以活动调度器只要判断iStatus != KRequestPending && iActive == ETrue则可以知道哪一个活动对象所请求的异步服务已经完成。
9、WaitForAnyRequest()等待异步函数返回通知,11、RequestComplete()并将iStatus的值改变
当异步服务已经完成了所请求的工作,它会使用User::RequestComplete()发送一个通知,活动调度器会通过 User::WaitForAnyRequest()或RThread::WaitForAnyRequest()收到这个通知,随后遍历向其注册的条件匹配的活动对象(第8点下划线部分说明)。
12、调用RunL方法
如果找到了异步函数所对应的活动对象,则调用活动对象的RunL方法,RunL方法在TRAP宏里运行。如果RunL方法抛出异常,活动调度器会自动调用活动对象的RunError方法。因此大多数情况下不需要在RunL内编写异常捕获的代码。
活动对象调用完RunL方法后,将活动对象的iActive值设置为EFalse,以便在下次遍历集合时跳过已经处理过的活动对象。
如果没有找到异步函数所对应的活动对象,活动调度器将抛出一个“信号迷失”异常。
13、CActiveScheduler::Stop()
停止活动调度器,停止监控异步函数返回的信号。
二、活动对象专属错误-“信号迷失”
从上面的分析我们知道,活动调度器会拦截异步函数返回的消息,随后遍历活动对象集合找到相应的活动对象调用,如果没有找到则抛出“信号迷失”异常。有以下两种方法会导致“找不到活动对象”的发生:
活动对象根本没有注册到活动调度器中:没有调用CActiveScheduler::Add方法注册活动对象
不满足活动调度器查找活动对象的标准iStatus != KRequestPending && iActive == ETrue:在调用异步函数后,没有调用SetActive()方法将iActive的值设为ETrue;或者将iStatus同时传给两个异步函数,导致第二个异步函数返回时,当前活动对象的iActive为EFalse,调度器找不到相应的活动对象。
三、小结
在这一节里,我们学习了活动对象的内部工作原理,让我们对活动对象处理机制有了更深入的了解。在下一节里,我们将学习如何同步调用现有的异步函数。
第4节 异步函数的同步调用
在上一节里我们深入了解了活动对象、活动调度器及异步函数服务器的工作原理及运行机制,想必大家对活动对象的机制及体系结构的运用已经了如指掌。但是大家有没有觉得异步函数使用起来比较麻烦呢?难道非要使用活动对象,非得以"异步"的方式调用异步函数吗?这一节将为大家解决这个问题:异步函数的同步使用。
一、使用CActiveSchedulerWait类
在以前的文章"Symbian编程总结-界面篇-打开jpeg/gif/png图像
"里我们已经看到了CActiveSchedulerWait类的使用方法,在此我再详细介绍一下。
很多初学者在开始时会将CActiveScheduler和CActiveSchedulerWait类弄混,CActiveScheduler是活动对象的调度器,而CActiveSchedulerWait可以简单的理解为一个当前线程的阻塞器:
* 调用CActiveSchedulerWait::Start()方法时,线程阻塞;
* 调用CActiveSchedulerWait::AsyncStop()方法时,请求停止对线程的阻塞
因此,我们在不修改原来活动对象代码的情况下,只要简单的在异步函数调用方法后加上"CActiveSchedulerWait::Start()",在活动对象的RunL方法的开头加入"CActiveSchedulerWait::AnsycStop()"就可以了。
针对上一节教程介绍的控制台应用程序,我们对以下几个方法(下划线为修改部分)进行修改:
点击此处下载源代码
CActiveSchedulerWait* iWait; void CMyActiveObject::ConstructL() { User::LeaveIfError(iTimer.CreateLocal() ); // Initialize timer CActiveScheduler::Add( this); // Add to scheduler iWait = new (ELeave)CActiveSchedulerWait; } CMyActiveObject::~CMyActiveObject() { Cancel(); // Cancel any request, if outstanding iTimer.Close(); // Destroy the RTimer object // Delete instance variables if any if (iWait->IsStarted()) { iWait->AsyncStop(); } delete iWait; iWait = NULL; } void CMyActiveObject::StartL(TTimeIntervalMicroSeconds32 aDelay) { Cancel(); // Cancel any request, just to be sure iTimer.After(iStatus, aDelay); // Set for later SetActive(); // Tell scheduler a request is active iWait->Start(); // 第1点 } void CMyActiveObject::RunL() { iWait->AsyncStop(); // 第2点 TBuf<50> outputStr; outputStr.AppendNum(iCount); iConsole.Write(outputStr); iConsole.Write(_L("\n")); iCount++; }
使用CActiveSchedulerWait的几点注意事项:
1. CActiveSchedulerWait必须结合活动对象使用,而且使用方法只有以上代码介绍的那一种;
2. Start方法和AsyncStop方法必须成对出现;
3. 程序退出时要检查CActiveSchedulerWait是否在IsStarted()状态,如果是则调用AsyncStop方法。否则程序不能正常退出;
4. CActiveScheduler类内部有自己的静态指针,提供的静态方法都调用了内部的静态指针。而CActiveSchedulerWait 类没有内部静态指针,方法也不是静态的,我们必须自己管理CActiveSchedulerWait类的全局指针,在这点上程序要经过良好的设计。
二、使用User::WaitForRequest方法
如果不想使用活动对象,也不想使用难于管理的CactiveSchedulerWait,你可以使用User::WaitForRequest方法。以下是User::WaitForRequest方法的原型:
IMPORT_C static void WaitForRequest(TRequestStatus& aStatus);
此方法将等待异步函数服务器返回的信号量,然后匹配aStatus参数。如果接收到的信号与参数aStatus一一匹配,则跳过阻塞进入下一行代码,否则继续阻塞线程直到aStatus对应的信号通知返回。
User::WaitForRequest还有一个重载的方法,它可以监视两个信号的通知:
IMPORT_C static void WaitForRequest(TRequestStatus& aStatus1,TRequestStatus& aStatus2);
有了User::WaitForRequest,异步函数使用起来就变得非常方便,我们不需要创建活动对象,也不需要创建成员变量 TRequestStatus,只需要声明局部的TRequestStatus、局部的异步函数类,在异步函数调用之后,加入 User::WaitForRequest(status),就能够使线程阻塞在User::WaitForRequest处直到status对应的异步函数处理完成。
LOCAL_C void DoTestL() { RTimer timer; CleanupClosePushL(timer); User::LeaveIfError(timer.CreateLocal()); TRequestStatus status(KRequestPending); // 调用异步方法并将status传入 timer.After(status, 1000000); // 等待status对应的信号量,此处用了User::WaitForRequest方法将异步方法的调用模拟成同步 User::WaitForRequest(status); CleanupStack::Pop(&timer); } LOCAL_C void MainL() { TInt n = 0; TBuf<10> str; _LIT(KNewLine, "\n"); FOREVER { DoTestL(); str.Num(n); n++; console->Write(str); console->Write(KNewLine); } }
三、使用User::WaitForRequest方法的问题
User::WaitForRequest有时候不会正常运行,如:CImageDecoder::Convert方法:
IMPORT_C virtual void Convert(TRequestStatus* aRequestStatus, CFbsBitmap& aDestination, CFbsBitmap& aDestinationMask, TInt aFrameNumber = 0);
最后一个参数必须为EOptionAlwaysThread,User::WaitForRequest才能正常执行,个人认为 CImageDecoder::Convert如果没有加EOptionAlwaysThread参数的时候是使用"长线任务"(将在下一节介绍)实现的。所以,CImageDecoder::Convert方法应该按照如下方法调用:
TRequestStatus status(KRequestPending); CImageDecoder* decoder = CImageDecoder::FileNewL(iFs, aFileName, KMIMEType); decoder->Convert(&status, aBitmap, CImageDecoder::EOptionAlwaysThread); User::WaitForRequest(status); delete decoder; decoder = NULL;
四、小结
本文介绍了在如果将异步函数同步使用。其实在Symbian的早期编程中还有一种异步函数的同步方法,那就是在异步函数调用后使用 CActiveScheduler::Start()方法嵌套活动调度器。但是这种方法已经被Symbian 7.0后的CActiveSchedulerWait替代,在此处就不再介绍。在下一节里将介绍活动对象的长线任务(Long-Running Task)。
另:在介绍活动对象的专题里涉及到很多Symbian OS的客户/服务器架构的知识,我会在近期另外开一个专题讲解,请大家耐心等待。
发表评论
-
Symbian 中的动态数组 CArrayX
2009-07-11 10:57 3316Symbian OS 中的动态数组CA ... -
Get application icon by uid
2009-06-25 00:36 957Following code sample can be us ... -
Symbian C++ 中本地化应用程序字符串
2009-06-24 23:40 1702详细描述 这个实例代码描述了如何本地化一个应用程序 ... -
Symbian系统错误码的解释
2009-06-24 01:22 3410Symbian 系统都会出现系 ... -
System panic reference常见panic
2009-06-24 01:14 17111、E32USER-CBase 63 只有Pop ... -
How to launch an application with its UID
2009-06-21 12:20 1351We can launch any application i ... -
如何在S60 3rd的手机上显示所有已安装程序的Uid
2009-06-21 00:25 1254一个应用程序它可以显示设备上所有已安装程序的Uid。 该程序 ... -
S60 平台: 比较ANSI C++ 和Symbian C++
2009-06-08 00:17 2154这是学习Symbain C++ ...
相关推荐
### Symbian OS 之活动对象详解 #### 一、Symbian OS 活动对象的引入背景与意义 Symbian OS 是一款专为移动设备设计的多任务操作系统,其核心特性之一便是通过引入活动对象(Active Objects)的概念,以实现高效且...
活动对象是Symbian OS操作系统中的一个重要概念,它在处理异步操作时起着关键作用。活动对象的设计目的是为了管理那些非阻塞的异步函数,使得应用可以在等待某些操作完成的同时,继续执行其他任务,提高了系统的并发...
在Symbian操作系统中,活动对象(Active Object)是一个核心概念,用于处理异步操作,尤其是在需要长时间运行或非阻塞...通过理解活动对象的工作原理和使用方式,开发者可以更好地编写出适应Symbian OS环境的高效代码。
Symbian C++具有一系列独特特性,如叶子类(Leaves)、清理机制(Cleanup)、描述符(Descriptors)和活动对象(ActiveObject),这些特性旨在提高程序的健壮性和资源管理效率。Symbian OS历经多个版本迭代,从v6.0...
- 在Symbian OS中,一个线程可以有一个活动调度器,它按照一定的策略决定何时启动或切换活动对象,这个过程是非抢占式的,即活动对象执行到结束或者主动让出控制权。 - 用户可以自定义活动调度器,以适应特定的...
**Symbian OS:手机操作系统的先驱** Symbian OS是历史上最早广泛应用于智能手机的操作系统之一,尤其在2000年至2010年间,它在全球范围内占据了主导地位,尤其是在诺基亚等品牌手机中。这个操作系统以其灵活性、可...
C++是Symbian OS的主要编程语言,因为其效率高且支持面向对象编程,适合处理复杂的系统级任务。 本书的章节可能涵盖以下内容: 1. **Symbian OS简介**:介绍Symbian操作系统的起源、发展及其在移动设备中的角色。 ...
《Symbian OS游戏开发源码解析》 在移动操作系统的历史上,Symbian OS曾是智能手机领域的主导者,尤其在功能手机时代,它为众多设备提供了强大的平台支持。本资料集聚焦于“Games on Symbian OS”的源码分析,涵盖...
【Symbian OS 活动对象详解】 Symbian OS 是一款专为移动设备设计的多任务操作系统,为了高效地处理多任务并确保系统快速响应,它引入了一种独特的机制——活动对象(Activity Object)。活动对象的概念旨在简化...
《Symbian OS课件(10)》——探索Symbian OS中的活动对象 在移动操作系统领域,Symbian OS以其高效、安全和可扩展性而闻名,尤其是在早期智能手机市场占据主导地位。本课件重点讲解的是Symbian OS中的核心概念之一:...
活动对象是Symbian OS线程模型的一个重要组成部分,它允许代码在后台执行,同时不阻塞用户界面。下面我们将深入探讨Symbian活动对象的原理、设计模式以及如何通过`TestAOConsole`这个例子来理解它的用法。 1. **...
在Symbian操作系统中,活动对象(Active Objects)是实现异步编程的核心机制。这个概念在Symbian OS中占有非常重要的地位,因为它允许应用程序在等待I/O操作或其他长时间运行的任务完成时,仍然能够响应用户界面事件...
在Symbian操作系统中,活动对象(Active Objects)是实现多线程并发处理的核心机制。这个概念对于理解和编写高效、响应迅速的Symbian应用程序至关重要。在这个“symbian活动对象例子”中,我们将深入探讨如何利用...
《Symbian OS C++ 手机应用开发》是一本深度探讨Symbian操作系统上C++编程技术的书籍,其源码涵盖了1-2卷的内容。Symbian OS曾是智能手机领域的重要操作系统,尤其在诺基亚手机中广泛应用。通过学习这本书的源码,...
3. **同步与互斥**:在Symbian OS中,互斥锁(Mutexes)和事件对象(Event Objects)是实现线程同步的主要手段。互斥锁确保同一时间只有一个线程访问特定资源,而事件对象可以用来阻塞线程直到特定事件发生。 4. **...
《Symbian OS C++ 高效编程》与《Symbian OS Explained》是两本专注于Symbian操作系统开发的书籍,它们为开发者提供了深入理解Symbian OS架构、API以及C++高效编程技巧的重要资源。源码的提供使得读者能够通过实际...
全书共分为21章,分别介绍了Symbian OS中的类命名约定、异常退出、清除栈、两段构造、描述符、良好的描述符风格、动态的数组与缓冲区、使用活动对象的事件驱动多任务、活动对象、 Symbian OS的线程与进程、客户/...