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的整理

先就此主題所涉及之專有名詞做強調:


元件:指提供一個或數個物件類別的

ActiveX Server(或者說OLE Server)


行程

Process,程式的定址空間,程式的資料與程式本身都儲存在此一定址空間內,可視為程式活動的空間,是物件存在的地方,一個ActiveX Server(此指EXE)的執行個體具有一個Process


執行緒

Thread,為佔據一個OS分時作業的單位,程式的執行需要有Thread,一個程式的Process中若有多個Thread,可以同時進行多項工作,且佔用整個OS的分時單位比較多。

註:MSDN的中譯把Process譯為處理緒,而Thread譯為執行緒

(
國內講CC++比較有品的書都把Process譯為行程,而Thread譯為執行緒)

物件類別的六種Instancing

Private 只有元件內部可以使用,對外為不可見。
PublicNotCreatable Client端可引用(可見),但不可建立,可用於元件的CallBack行為。
SingleUse Client端所要求建立之每一個同類別的物件實體都具有自己的元件執行個體。
GlobalSingleUse 多了Global表示元件編譯後便成為全域物件,使用時無需先行引用。
MultiUse Client端所要求建立之每一個同類別的物件實體都使用同一個元件執行個體。
GlobalMultiUse 多了Global表示元件編譯後便成為全域物件,使用時無需先行引用。

 

ActiveX EXE

MultiUse物件別類測試所得之元件ProcessThread關係
VB中文版選項譯名 我自己的解釋

Client物件數

Process

每個

ProcessThread
獨立的執行緒 獨立的Thread

N

1

N+1

執行緒共用區1個執行緒 單一的Thread

N

1

1

執行緒共用區M個執行緒 共用MThread

N

1

N+1(N+1M)

SingleUse物件別類測試所得之元件ProcessThread關係
VB中文版選項譯名 我自己的解釋

Client物件數

Process

每個

ProcessThread
獨立的執行緒 獨立的Thread

N

N

1

執行緒共用區1個執行緒 單一的Thread

N

N

1

執行緒共用區M個執行緒 共用MThread

N

N

1

註:此測試中的Client端均為單一Process。

 

 

執行緒模型

(獨立/共用n個行程)

類別

Instancing
(SingleUse/MultiUse)

意義

元件執行個體是否為多Thread獨立執行緒的元件執行個體為每一個物件實體與其自身建立一個Thread,所以一共是(物件數目+1)Thread

  元件執行個體中的一個物件實體在執行一項工作時,必需由元件執行個體所擁有一個

Thread負責供提CPU的使用權。元件若可以擁有多個Thread,表示可以讓多個物件實體同時工作而不需等待佔據Thread的物件釋放Thread。若把元件的執行緒模型設為共用一個以上的執行緒,即等於公寓模型。
SingleMulti指的是Client端所建立的物件實體如何存在於元件執行個體(即元件的Process)中,也就是元件的執行個體中是否能存在一個以上相同類別的物件(SingleUse不行,MultiUse可以)。若該元件中提供了不只一個物件類別,則會在SingleUse類別的物件不重複的情況下共用同一個元件執行個體。一旦SingleUse類別的物件被呼叫端建立超過一個以上,則將自動產生另一個元件的執行個體(Process),並在新的元件執行個體中產生呼叫端所要求建立的SingleUse類別之物件。

影響

同一元件執行個體(Process)中不同的物件是否能一起運作。 由於物件存在的空間不同(Process不同)SingleUse物件無法與同類別物件之間共用全域資料。只有MultiUse的物件可以共用全域資料,且享有單一Process,多重Thread的好處。

 

        不論是ActiveX DLLActiveX EXE,能否共用一般模組中Public變數的關鍵即在於物件實體是否存在於相同的元件執行個體(Process)。由於ActiveX DLL是屬於In-Process的元件,故而其中之物件類別模組沒有SingleUseInstancing,以其提供之類別來產生的物件實體是存在於Client端的Process中,若多個物件同時存在於Client端的同一Process中,則可共用一般模組中Public變數。以Out-ProcessActiveX EXE而言,若Client端所建立的物件為SingleUse,則不論把元件專案的執行緒模型設成什麼,都一律為每一個物件產生新的元件執行個體(Process);若物件類別為MultiUse,而元件專案的執行緒模型為獨立的執行緒,則會在同一個元件執行個體(Process)中建立多個Thread以對應每一個Client端所建立的物件實體。

結論

物件類別的
SingleUse / MultiUse所影響的是元件是否為MultiProcess;元件執行緒模型的「獨立或共用N / 共用1」所影響的是元件是否為MultiThread