2007-10-25 22:38:13
Kenny
ActiveX .Exe .Dll Server的多執行緒
來源:cww / AKL ActiveX .exe .dll Server都可以設定成多執行緒,但手冊上面得大多有看沒有 懂,尤其是Project本身可設定多執行緒,而Class又可設定成MultiUSe,搞得不是 很清楚,在經過一些testing後,整理出一些東西,以補足手冊上的不清楚,看完它 再去看手冊的說明就會比較清楚啦(我想)。如果我的觀念有誤,也請更正。 MyProject 假設有一個ActiveX Server,其內有一個Class和.bas Module組成 | +- Class | | | +--- MyClass | Public cp as long | Private cv as Long | Public Sub cFunc1() | . | . | End Function | Public Sub cFunc2() | . | . | End Sub | +- Module | +--- MyBas.Bas Public basVar as long Public Sub Sub1() . . End Sub 一、Myproject為ActiveX .exe Server 1.MyProject設定成單一執行緒 a.Myclass 為MultiUse 表示該Class的每一個Instance都是固定由某一個Thread來執行, 所謂MultiUse便是單一個執行緒可對多個Instance提供服務 client A 的程式 client B 的程式 dim aa as New MyClass dim bb as New Myclass Call aa.cFunc1 Call bb.cFunc2 如上例,ClientA ClientB同時對某一部電腦上的MyProject提出需求, 此時,第一個呼叫它的程式(假設是Call aa.cFunc1)將該Server叫起來了, 如果此時ClientB也對之提出要求,那麼的ClinetA aa這個instance和 Client B的bb Instance共用同一個Thread,也就是說這兩個Instance必 需進入排程,共用一個Thread的情況又有什麼特性呢?此時aa, bb共用 MyBas.Bas內的資料,如上例中的basVar會共用,不論是改了它都會影響 另一個人,但是bb, aa這兩個Class Instance有自己的變數,即aa 有自己 cp, cv的變數,bb也有自己的,這就是所謂的公寓模式,在.clx內的東西 各人有各人的,但共用.bas的資料。以這個例子來說,如果aa.cFunc1已在 執行,而且它是一個Long Job,而 bb.cFunc2也要來執行時,它便得進入 Queue中等待,所以會有交通阻塞的情況。 b.SingleUse 表示某個Class的instance 只在一個Thread上執行,同樣以上面的例子來看 aa 這個Instance產生了,那它在Thread1 上執行,而同時bb也產生了,那 它會在另一個Thread2上執行,而Thread1, Thread2本身有自己的區域資料 ,所以aa, bb就不會用MyBas.Bas內的任何資料,正因aa, bb在不同的thread 上執行,所以它們兩個便以排程的方式來執行,不會有誰先做,另一個人一定 得等,aa的thread先做,做了一段時間後會Swap變bb的Thread做,所以有可能 bb.cFunc2先完成。但缺點是浪費Resource。不要被MyProject的單一執行緒給 騙了,它是設成單一執行緒,但Class設成SingleUse時,仍有可能是 MultiThread的Server 另一個例子: Myproject中有二個Class,Class1為MultiUse, Class2為SingleUse 且有一個MyBas.Bas Module Dim aa as New Class1 Dim bb as New Class1 Dim aa2 as New Class2 Dim bb2 as New Class2 aa.method1 aa2.method2 bb.func1 bb2,func2 則aa, aa2, bb 共用mybas.bas之資料,bb2沒有共用,aa, bb同一個thread 沒有問題,aa2呢?那是因為SingleUse對象是Class,方才的thread雖有aa, bb 於其上,但那是Class1, Class2尚未有Instance於thread上,故選擇方才的 thread來執行,而bb2自然得在另一個Thread上啦。這個前提是只有一個Client 來執行,如果有兩個以上Client時,我們不知執行的前後順序,所以不易預測 誰和誰共用資料。而我們可透過App.ThreadId來取得Thread的id,以上例來說 如果於Class1, Class2中各有引用App.ThreadId時,會發現aa, aa2, bb所取得 的是相同的,而bb2所取得者不相同。 2.MyProject設成多執行緒 假設我們設定MyProject有4個Thread (T1 to T4) T1 | | T4 ---+---- T2 | | T3 如果有Client1 to 3 呼叫Server的順序如下 ClassA (multiUse) client1 要求 ClassA -->A1 則於 T1執行 ClassB (MultiUse) client2 要求 ClassA -->A2 .. T2 .. ClassC (multiUse) client1 .. ClassB -->B1 .. T3 .. Mybas.bas client3 .. ClassC -->C3 .. T4 .. client2 .. ClassC -->C2 .. T1 .. client1 .. ClassC -->C1 .. T2 .. 也就是說,Client 端每產生一個Instance,該Instance便會一在下一個Thread上 執行,如此的循環,所以這個例子來看,變成A1, C2共用mybas.bas的資料,A2, C1 是另一組共用者。如此造成誰和共用資料十分不明確,不過定的是每個.clx都有自己 的資料,符合公寓式模型。 另外,如果Instance A1(Client1所產生的ClassA Instance)於T1中執行,而A1中 去Create Instance B時,If使用New指令則Instance B也在T1中執行,故和A1共用 Mybas.Bas但,使用CreateObject則Instabce B會在T2中執行。 至於三個Class中有一個是SingleUse時會如何,本人已沒有再測下去,可以知道的是 SingleUse的Class會找一個沒有執行同一Class的Thread來執行,但如果4個Thread 都有時,會不會產生第五個Thread來做,可能吧,沒有力testing了。 3.MyProject設成獨立執行緒 同多執行緒,只是沒有限制thread個數。 二、MyProject 是ActiveX. Dll Server 因是.Dll 的方式存在,所以Class不可能是SingleUse,因為一個Process 一不能有相同的兩份.dll 1.MyProject設單一執行緒 客戶端多執行緒.exe 有Thread 1 -3 thread1, thread2, thread3同時要求該class時,則後到的要等待 前面的處理完才能做,因該Server只有單一執行緒。各個Instance 共用.Bas內的資料。 2.MyProject設成公寓模型(多執行緒) 同上的狀況來說,Thread1- 3 對該Class的運作,就沒有誰等誰的情況。 因為 多執行緒.exe的各個Thread,都定義了Dll Server中的一問公寓 ,所有在執行緒中所建之的物件都住在該執行緒定義的公寓中,除非Thread3 使用Thread2的物件方法,那這呼叫會被排在Thread2本身目前正在處理的 物件之後(循序化)。以下是AKL的整理
先就此主題所涉及之專有名詞做強調:
元件:指提供一個或數個物件類別的
行程
執行緒:
註:MSDN的中譯把Process譯為處理緒,而Thread譯為執行緒…
(國內講C或C++比較有品的書都把Process譯為行程,而Thread譯為執行緒)
物件類別的六種Instancing | |
Private | 只有元件內部可以使用,對外為不可見。 |
PublicNotCreatable | Client端可引用(可見),但不可建立,可用於元件的CallBack行為。 |
SingleUse | Client端所要求建立之每一個同類別的物件實體都具有自己的元件執行個體。 |
GlobalSingleUse | 多了Global表示元件編譯後便成為全域物件,使用時無需先行引用。 |
MultiUse | Client端所要求建立之每一個同類別的物件實體都使用同一個元件執行個體。 |
GlobalMultiUse | 多了Global表示元件編譯後便成為全域物件,使用時無需先行引用。 |
ActiveX EXE | ||||
以 MultiUse物件別類測試所得之元件Process與Thread關係 | ||||
VB中文版選項譯名 | 我自己的解釋 |
Client物件數 |
Process數 |
每個 Process的Thread數 |
獨立的執行緒 | 獨立的Thread |
N |
1 |
N+1 |
執行緒共用區1個執行緒 | 單一的Thread |
N |
1 |
1 |
執行緒共用區M個執行緒 | 共用M個Thread |
N |
1 |
N+1(N+1≦M) |
以 SingleUse物件別類測試所得之元件Process與Thread關係 | ||||
VB中文版選項譯名 | 我自己的解釋 |
Client物件數 |
Process數 |
每個 Process的Thread數 |
獨立的執行緒 | 獨立的Thread |
N |
N |
1 |
執行緒共用區1個執行緒 | 單一的Thread |
N |
N |
1 |
執行緒共用區M個執行緒 | 共用M個Thread |
N |
N |
1 |
註:此測試中的Client端均為單一Process。 |
執行緒模型 (獨立/共用n個行程) |
類別 Instancing (SingleUse/MultiUse) | |
意義 |
元件執行個體是否為多Thread。獨立執行緒的元件執行個體為每一個物件實體與其自身建立一個Thread,所以一共是(物件數目+1)個Thread。
元件執行個體中的一個物件實體在執行一項工作時,必需由元件執行個體所擁有一個 Thread負責供提CPU的使用權。元件若可以擁有多個Thread,表示可以讓多個物件實體同時工作而不需等待佔據Thread的物件釋放Thread。若把元件的執行緒模型設為共用一個以上的執行緒,即等於公寓模型。 |
Single和Multi指的是Client端所建立的物件實體如何存在於元件執行個體(即元件的Process)中,也就是元件的執行個體中是否能存在一個以上相同類別的物件(SingleUse不行,MultiUse可以)。若該元件中提供了不只一個物件類別,則會在SingleUse類別的物件不重複的情況下共用同一個元件執行個體。一旦SingleUse類別的物件被呼叫端建立超過一個以上,則將自動產生另一個元件的執行個體(Process),並在新的元件執行個體中產生呼叫端所要求建立的SingleUse類別之物件。 |
影響 |
同一元件執行個體(Process)中不同的物件是否能一起運作。 | 由於物件存在的空間不同(Process不同),SingleUse物件無法與同類別物件之間共用全域資料。只有MultiUse的物件可以共用全域資料,且享有單一Process,多重Thread的好處。 |
不論是ActiveX DLL或ActiveX EXE,能否共用一般模組中Public變數的關鍵即在於物件實體是否存在於相同的元件執行個體(Process)中。由於ActiveX DLL是屬於In-Process的元件,故而其中之物件類別模組沒有SingleUse的Instancing,以其提供之類別來產生的物件實體是存在於Client端的Process中,若多個物件同時存在於Client端的同一Process中,則可共用一般模組中Public變數。以Out-Process的ActiveX EXE而言,若Client端所建立的物件為SingleUse,則不論把元件專案的執行緒模型設成什麼,都一律為每一個物件產生新的元件執行個體(Process);若物件類別為MultiUse,而元件專案的執行緒模型為獨立的執行緒,則會在同一個元件執行個體(Process)中建立多個Thread以對應每一個Client端所建立的物件實體。
結論
:物件類別的SingleUse / MultiUse所影響的是元件是否為MultiProcess;元件執行緒模型的「獨立或共用N個 / 共用1個」所影響的是元件是否為MultiThread。