Active Object (AO) 框架,是Symbian的基本工作部分。它是為了滿足多個任務同時執(zhí)行的要求。在 Windows/Unix 平臺上,我們可以不加思索的使用多線程來完成多任務。可是在嵌入式平臺上,系統(tǒng)的資源是有限的。比如CPU、內存都比我們平時用的個人計算機要低。這就要求嵌入式系統(tǒng)能夠合理的使用系統(tǒng)資源。不能頻繁的切換線程或者進程。
Symbian為這種特別需求設計了Active Object (AO)框架。AO框架是運行于一個線程內部的調度框架。其基本思想就是把一個單線程分為多個時間片,來運行不同的任務。
這和多線程有很大區(qū)別。多線程之間是可以被搶占的(由操作系統(tǒng)調度),但是AO框架中的各個任務是不可被搶占的,一個任務必須完成,才能開始下一個任務。
下面是多線程和AO框架的簡單比較:
多線程 AO框架
可以被搶占 不可被搶占
上下文切換耗費CPU時間 沒有上下文切換
由操作系統(tǒng)調度 由線程自己的AO框架調度
每個線程都有至少4K Stack. AO沒有單獨的Stack.
操作系統(tǒng)還要分配額外的資源記錄線程 只是一個Active Object.
Symbian系統(tǒng)本身使用了大量的AO框架來實現一些系統(tǒng)服務。這使得Symbian和其他嵌入式系統(tǒng)相比較,對系統(tǒng)資源的使用更加合理。
AO框架包括CActiveScheduler 和CActive (Active Object)。一個線程的所有的Active Object對象都被安裝在該線程的CActiveScheduler對象內.由CActiveScheduler對象監(jiān)控每個Active Object是否完成了當前任務,如果完成了,就調度下一個Active Object來執(zhí)行。CActiveScheduler根據優(yōu)先級來調度各個Active Object.
關于CActiveScheduler的創(chuàng)建和安裝,CActive的創(chuàng)建和安裝,和CActive的任務處理,可以參看 SDK 文檔。理解起來不難。下面要說一個比較容易忽略的地方。這對理解AO框架非常重要。
創(chuàng)建調度器:
CActiveScheduler * scheduler = new (ELeave) CActiveScheduler;
CleanupStack::PushL(scheduler);
CActiveScheduler::Install(scheduler);
運行調度器:
CActiveScheduler::Start();
停止調度器:
CActiveScheduler::Stop();
以上代碼都是運行在一個線程中的,一般來講,一個EXE只有一個主線程.
可是如果真的有2個線程呢?
為什么在當前線程下調用CActiveScheduler::Start(),CActiveScheduler::Stop()運行/停止的就是當前線程的調度器而不是另一個線程的調度器?
每個線程都有自己的CActiveScheduler,那么這個CActiveScheduler類是怎么調用CActiveScheduler::Start(),CActiveScheduler::Stop()來運行/停止當前的調度器的呢?
我們看到Start/Stop并沒有參數.
打開CActiveScheduler的類定義:
class CActiveScheduler : public CBase
{
public:
IMPORT_C CActiveScheduler();
IMPORT_C ~CActiveScheduler();
IMPORT_C static void Install(CActiveScheduler* aScheduler);
IMPORT_C static CActiveScheduler* Current();
IMPORT_C static void Add(CActive* anActive);
IMPORT_C static void Start();
IMPORT_C static void Stop();
IMPORT_C static TBool RunIfReady(TInt& aError, TInt aMinimumPriority);
IMPORT_C static CActiveScheduler* Replace(CActiveScheduler* aNewActiveScheduler);
IMPORT_C virtual void WaitForAnyRequest();
IMPORT_C virtual void Error(TInt anError) const;
private:
void DoStart();
void OwnedStartLoop(TInt& aRunning);
IMPORT_C virtual void OnStarting();
IMPORT_C virtual void OnStopping();
IMPORT_C virtual void Reserved_1();
IMPORT_C virtual void Reserved_2();
private:
// private interface used through by CActiveSchedulerWait objects
friend class CActiveSchedulerWait;
static void OwnedStart(CActiveSchedulerWait& aOwner);
protected:
inline TInt Level() const;
private:
TInt iLevel;
TPriQue<CActive> iActiveQ;
};
我們并沒有看到靜態(tài)的成員來表示線程,但是卻有一個static函數CActiveScheduler* Current();返回當前線程的調度器.
現在猜想奧秘就在這個函數是怎么實現的。這個靜態(tài)的函數怎么就能得到當前這個運行線程的調度器,而不是別的線程的調度器。我們可以猜想,肯定是Current()內部實現能取到當前線程的標識信息.用這個標識,靜態(tài)函數能取到這個線程的CActiveScheduler.這個具體如何實現呢?
答案就是:當前線程的線程ID可以這樣得到:
創(chuàng)建一個缺省的線程對象:
RThread thread;
取得當前線程的ID:
TThreadId threadId = thread.Id();
能得到當前線程的threadId,當然可以得到和當前線程關聯的CActiveScheduler。因此以上兩個問題也就迎刃而解了,在一個線程內調用CActiveScheduler::Start(),CActiveScheduler::Stop()開啟的就是當前線程。
既然回復了上面的問題,那么我們自然就能明確,在一個線程內是不能通過Start和Stop函數來開啟和停止另一個線程內的活動對象規(guī)劃器CActiveScheduler。
補充點其他東西:
在Symbian操作系統(tǒng)中,每個進程都有一個或多個線程。線程是執(zhí)行的基本單位。一個進程的主線程是在進程啟動時生成的。Symbian屬于搶占式多任務操作系統(tǒng),這意味著每個線程都有自己的執(zhí)行時間,直到系統(tǒng)將CPU使用權給予其他線程。當系統(tǒng)調度時,具有最高優(yōu)先權的線程將首先獲得執(zhí)行。
進程邊界是受內存保護的。所有的用戶進程都有自己的內存地址空間,同一進程中的所有線程共享這一空間,用戶進程不能直接訪問其他進程的地址空間。
每個線程都有它自己的stack和heap,這里heap可以是私有的,也可以被其他線程共享。應用程序框架生成并安裝了一個active scheduler,并且為主線程準備了清除棧。如果沒有使用框架(如編寫exe程序)那就要手動生成這些了。
Symbian操作系統(tǒng)專為單線程應用優(yōu)化,因此強烈推薦使用“活動對象”代替多線程。
posted on 2008-10-11 20:34
frank.sunny 閱讀(2679)
評論(2) 編輯 收藏 引用 所屬分類:
symbian 開發(fā)