2012年2月9日

[.Net] Thread Local Storage

Thread Local Storage(TLS),顧名思意就是在 Thread 裡的儲存空間,
在 MultiThread 的世界裡面,Thread 和 Thread 之間本來就井水不河水,
要存取共用的資源時,就要透過鎖定同步等方式,才不會有競速的問題,
TLS 要解決的問題,並不是 Thread 之間資源共享的問題,
而是 Thread 本身資源共享的問題。

假設我們要設計一個 ADODB 物件,
讓程式都透過底層取得 ADODB 物件,再使用 ADODB 物件執行 SQL ,
而 Connection 的事都交給 ADODB 物件處理,
程式只需要
ADODB dbAdpter = ADODBFactory.getADODB();
dbAdpter.execSQL(...);
而 ADODB 物件的設計,會盡量使用同一條 Connection ,
void main()
{
    methodA();
    methodB();
}

void methodA() {
    ADODB dbAdpter = ADODBFactory.getADODB();
    dbAdpter.execSQL("...");  
}

void methodB() {
    ADODB dbAdpter = ADODBFactory.getADODB();
    dbAdpter.execSQL("...");  
}
如上面程式所示,
這邊會希望每次從 ADODBFactory.getADODB() 取出來的物件是同一個,
而 connection 就 keep 在這裡面,
對 ADODBFactory 而言,並不曉得呼叫他的是不是同一個 thread ,
他也不能隨便丟一個 ADODB 回去,如果每次都 new 一個 ADODB 的話,
就變成會開一堆 connection ,即使有用 ado.net 的 connection pooling ,
connection 用量還是很大,更慘的是,如果有 transctionscope 還會被升級成 DTC,
如果 ADODBFactory 能夠從 thread 中取得現有的 ADODB ,
沒有的時候就 new 一個給他,這樣就完美了,
所以我們需要在 thread 中佈置一塊空間,而且讓 thread 外面可以看得到,拿得到,
這時候 TLS 就很好用了,直接就在 thread 上放一個俱名的 Data Slot ,
ADODBFactory.getADODB 就先看目前 thread 裡有沒有存在的 ADODB 物件,
如果有就直接拿,沒有的話就 new 一個給他。
public static ADODB getADODB()
{
    if (Thread.GetData(Thread.GetNamedDataSlot("YourDataSlotID"))==null) {
        Thread.SetData(Thread.GetNamedDataSlot("YourDataSlotID"), newADODB());
    }
    return (ADODB)Thread.GetData(Thread.GetNamedDataSlot("YourDataSlotID"));
}
於是我們就很輕鬆的用 TLS 完成這個任務了。

參考資料:
Thread Local Storage: Thread-Relative Static Fields and Data Slots

沒有留言 :

張貼留言