2011-03-08 59 views
105

[ThreadStatic]屬性如何工作?我認爲編譯器會發出一些IL來填充/檢索TLS中的值,但是看到反彙編似乎並沒有在這個層次上做到這一點。ThreadStatic屬性如何工作?

作爲一個後續,如果你把它放在非靜態成員上會發生什麼?我們有一個開發人員犯了這個錯誤,編譯器甚至沒有提出警告。

更新

第二個問題回答這裏:ThreadStatic Modified with Static C#

+1

如果生成的IL是相同的(確實是這樣),那麼運行時必須特別編碼,以知道如何分配和讀取值,當它擊中這樣一個裝飾字段。看起來像一個黑客:) – 2011-03-08 02:45:13

回答

75

在.NET JIT編譯器中,線程靜態的實現語義低於IL級別。像VB.NET和C#一樣發佈到IL的編譯器不需要知道任何關於Win32 TLS的內容,就可以發出IL代碼來讀寫具有ThreadStatic屬性的變量。只要C#知道這個變量沒有什麼特別之處 - 它只是一個讀取和寫入內容的位置。它對它有一個屬性的事實對C#沒有任何影響。 C#只需要知道如何爲該符號名稱發送IL讀取或寫入指令。

'繁重'由核心CLR完成,負責使IL在特定的硬件架構上工作。

這也可以解釋爲什麼將屬性放在不合適的(非靜態)符號上不會得到編譯器的反應。編譯器不知道該屬性需要什麼特殊的語義。代碼分析工具如FX/Cop應該知道它。

另一種查看方式:CIL定義了一組存儲範圍:靜態(全局)存儲,成員存儲和堆棧存儲。 TLS不在該列表中,很可能是因爲TLS不需要在該列表中。如果IL讀寫指令足以在TLS屬性標記符號時訪問TLS,爲什麼IL對TLS有特殊的表示或處理?這不是必需的。

97

如何[ThreadStatic]屬性 工作?

您可以認爲標記爲ThreadStatic的字段已附加到線程,並且其生存期與線程的生命週期相當。

所以僞ThreadStatic是(通過語義)與具有連接到一個線程鍵值:

Thread.Current["MyClass.myVariable"] = 1; 
Thread.Current["MyClass.myvariable"] += 1; 

但語法是隻是更容易一點:

class MyClass { 
    [ThreadStatic] 
    static int myVariable; 
} 
// .. then 
MyClass.myVariable = 1; 
MyClass.myVariable += 1; 

如果你把它放在非靜態成員上會發生什麼?

我相信它會被忽略:

class A { 
     [ThreadStatic] 
     public int a; 
    } 
    [Test] 
    public void Try() { 
     var a1 = new A(); 
     var a2 = new A(); 
     a1.a = 5; 
     a2.a = 10; 
     a1.a.Should().Be.EqualTo(5); 
     a2.a.Should().Be.EqualTo(10); 
    } 

另外值得一提的是,相比於普通的靜態字段(因爲狀態不共享)ThreadStatic不需要任何同步機制。

+1

第二個像僞代碼應該是'「MyClass.myVariable」',不是嗎? – akshay2000 2016-09-18 11:50:25

+0

我不確定確切的限制條件,但我只想指出,如果它不一定是原始類型並不明顯。如果您查看「TransactionScope」的源代碼,他們會爲該範圍存儲各種內容(https://referencesource.microsoft.com/#System.Transactions/System/Transactions/Transaction.cs,0e19ea1e3a994306) – 2017-03-27 02:15:21