[轉自MSDN]可靠性最佳做法

來源:互聯網
上載者:User
可靠性最佳做法

下列可靠性規則是面向 SQL Server 的;但它們也適用於任何基於宿主的伺服器應用程式。對於 SQL Server 這類伺服器而言,不泄漏資源且不降低效能極其重要。但是,並不能通過為每個更改對象狀態的方法編寫結束代碼來實現這兩個目標。我們的目標不是編寫 100% 可靠並能夠通過結束代碼從任意位置的任何錯誤中進行恢複的Managed 程式碼。那樣做的話任務過於艱巨,且成功的可能性微乎其微。公用語言運行庫 (CLR) 難以為Managed 程式碼提供足夠強的保證,因此要編寫完美的代碼很不現實。注意,與 ASP.NET 不同,SQL Server 僅使用一個進程,且只有將資料庫關閉一段時間後才能回收該進程,而且這段時間長得不可接受。

由於這些保證較弱且又以單進程運行,因此要實現可靠性,則需要在必要時終止線程或回收應用程式定義域,並且採取預防措施來確保不泄漏作業系統資源(如控制代碼或記憶體)。即使在這樣較為簡單的可靠性約束下,仍然存在一個非常重要的可靠性要求:

  • 任何情況下都不要泄漏作業系統資源。

  • 向 CLR 標識所有形式的所有託管鎖。

  • 任何情況下都不要破壞跨應用程式定義域共用狀態,以便使 AppDomain 回收順利進行。

儘管理論上可以編寫Managed 程式碼來處理 ThreadAbortException、StackOverflowException 和 OutOfMemoryException 異常,但希望開發人員在整個應用程式範圍內編寫這樣可靠的代碼則很不切實際。因此,帶外異常會導致執行線程終止;如果被終止的線程正在編輯共用狀態(可由該線程是否持有鎖來確定),則 AppDomain 會被卸載。正在編輯共用狀態的方法終止時,共用狀態會被損壞,因為無法編寫可靠的結束代碼來更新共用狀態。

在 .NET Framework 2.0 版中,SQL Server 是唯一有可靠性要求的宿主。如果程式集將在 SQL Server 上運行,那麼即使某些特定功能在資料庫中運行時是禁用的,也應對該程式集的每個部分進行可靠性處理。之所以必須這樣做,是因為程式碼分析引擎在程式集層級檢查代碼,無法區分出禁用的代碼。進行 SQL Server 編程時還有一點需要注意,即 SQL Server 是在一個進程中運行所有內容,並使用 AppDomain 回收清理所有資源(如記憶體和作業系統控制代碼)。

不能依賴於終結器、解構函式或 try/finally 塊作為結束代碼。它們可能會被中斷或不被調用。

非同步異常可在意外的位置引發,並且可能由每個電腦指令引發:ThreadAbortExceptionStackOverflowExceptionOutOfMemoryException

託管線程不一定是 SQL 中的 Win32 線程;也可能是纖程。

很難安全更改進程範圍或跨應用程式定義域的可變共用狀態,因此應儘可能避免此類操作。

記憶體不足的情況在 SQL Server 中並不少見。

如果寄宿在 SQL Server 中的庫沒有正確地更新其共用狀態,代碼就很可能不會在資料庫重新啟動前恢複。此外,在某些極端情況下,還可能導致 SQL Server 進程失敗,使資料庫重新啟動。重新啟動資料庫可使網站關閉或影響公司運營,從而影響可用性。作業系統資源(如記憶體或控制代碼)的緩慢泄漏可能導致伺服器最終無法分配控制代碼並且無法恢複,也可能導致伺服器的效能緩慢下降並使客戶應用程式可用性降低。很顯然我們要避免這類情況。

最佳做法規則

要重點介紹的是,為了提高架構的穩定性和可靠性,在對伺服器中啟動並執行Managed 程式碼進行代碼檢查時必須捕捉什麼。所有這些檢查通常都是良好的做法,而且絕對必須在伺服器上進行。

遇到死結或資源約束時,SQL Server 將中止線程或拆開 AppDomain。發生這種情況時,僅保證運行受約束執列區域 (CER) 中的結束代碼。

使用 SafeHandle 避免資源泄漏

AppDomain 被卸載的情況下,不能依賴 finally 塊或終結器的執行,因此,通過 SafeHandle 類而不是 IntPtr、HandleRef 或類似的類來抽象所有作業系統資源訪問就很重要。這樣可使 CLR 跟蹤和關閉控制代碼(甚至是在 AppDomain 被拆開的情況下使用的控制代碼)。SafeHandle 將使用 CLR 始終啟動並執行關鍵終結器。

作業系統控制代碼從建立時起至釋放前都儲存在安全控制代碼中。任何視窗中都不會出現引發控制代碼泄漏的 ThreadAbortException。此外,平台叫用將對控制代碼進行引用計數(這樣可密切跟蹤控制代碼的生存期),通過 Dispose 與當前使用該控制代碼的方法之間的競爭條件來防止安全性問題的出現。

當前僅使用終結器清理作業系統控制代碼的大多數類將不再需要終結器。SafeHandle 衍生類別才使用終結器。

注意,SafeHandle 並不替換 System.IDisposable.Dispose。顯式釋放作業系統資源還可能具有處理資源爭用和提高效能的優點。注意,顯式釋放資源的 finally 塊可能不會完全執行。

SafeHandle 允許實現您自己的 ReleaseHandle 方法來執行釋放控制代碼的工作,如將狀態傳遞給釋放常式的作業系統控制代碼或釋放迴圈中的一組控制代碼。CLR 保證此方法的運行。確保控制代碼在任何情況下都能得到釋放是實現 ReleaseHandle 的創作者的責任。如果不這樣做,則會導致控制代碼泄漏,通常也會因此導致與控制代碼關聯的本機資源泄漏。因此,構造 SafeHandle 衍生類別使 ReleaseHandle 實現不要求分配任何在調用時停用資源是非常重要的。注意,可以在 ReleaseHandle 的實現中調用可能失敗的方法,但要求您自己的代碼能夠處理此類失敗並完成釋放本機控制代碼的約定。為了進行調試,ReleaseHandle 具有一個 Boolean 傳回值,如果遇到阻止資源釋放的重大錯誤,該值會被設定為 false。這樣可啟用 ReleaseHandleFailed MDA(如果啟用)以協助確定問題。它不以任何其他方式影響運行時;對於同一資源將不再調用 ReleaseHandle,因此會導致控制代碼泄漏。

SafeHandle 不適用於某些上下文。由於 ReleaseHandle 方法可以在 GC 終結器線程上使用,因此,任何需要在特定線程上釋放的控制代碼都不應封裝在 SafeHandle 中。

運行庫可調用封裝 (RCW) 無需其他代碼即可由 CLR 清理。對於使用平台叫用並將 COM 物件作為 IUnknown*IntPtr 處理的代碼,應重新編寫代碼以使用 RCW。由於非託管釋放方法可能回調Managed 程式碼,因此SafeHandle 可能不適合這種情況。

程式碼分析規則

使用 SafeHandle 封裝作業系統資源。不要使用 HandleRefIntPtr 類型的欄位。

確保不必運行終結器防也可防止作業系統資源泄漏

仔細檢查終結器,確保即使不運行這些它們也不會泄漏重要的作業系統資源。與應用程式在穩定點下執行時或 SQL Server 等伺服器關閉時的正常 AppDomain 卸載不同,突然的 AppDomain 卸載期間對象不會終結。要確保資源在突然卸載的情況下不會泄漏,因為不能保證應用程式的正確性,但卻必須通過不泄漏資源來維持伺服器的完整性。可使用 SafeHandle 釋放所有作業系統資源。

確保不必運行 finally 子句也可防止作業系統資源泄漏

finally 子句不能保證在 CER 之外也能運行,這要求庫開發人員不要依賴 finally 塊中的代碼來釋放非託管資源。建議的解決方案是使用 SafeHandle

程式碼分析規則

使用 SafeHandle 而不要使用 Finalize 來清理作業系統資源。不要使用 IntPtr;應使用 SafeHandle 封裝資源。如果必須運行 finally 子句,請將其放置在 CER 中。

所有的鎖應遍曆現有託管鎖定代碼

CLR 必須知道代碼何時鎖定,這樣才會知道停止 AppDomain 而不僅僅是中止線程。中止線程可能會有危險,因為線程操作的資料所保留的狀態可能不一致。因此,必須回收整個 AppDomain。未能識別鎖可能造成死結或錯誤的結果。使用 BeginCriticalRegion 和 EndCriticalRegion 方法可識別鎖地區。這兩個方法是 Thread 類的靜態方法,僅應用於當前線程,有助於防止線程編輯其他線程的鎖計數。

Enter 和 Exit 內建此 CLR 通知,因此建議使用這些方法和 lock 語句(C# 參考)(該語句使用這些方法)。

其他鎖定機制(如數值調節鎖和 AutoResetEvent)必須調用這些方法來通知 CLR 已進入臨界區。這些方法不使用任何鎖;它們通知 CLR 代碼正在臨界區中執行,中止線程可能會使共用狀態不一致。如果定義了自己的鎖類型,如自訂 ReaderWriterLock 類,請使用這些鎖計數方法。

程式碼分析規則

使用 BeginCriticalRegionEndCriticalRegion 標記和識別所有鎖。不要在迴圈中使用 CompareExchange、Increment 和 Decrement。不要對這些方法的 Win32 變數執行平台叫用。不要在迴圈中使用 Sleep。不要使用可變欄位。

清除代碼必須位處於 finally 或 catch 塊中,不能處於 catch 之後

任何情況下清除代碼都不應在 catch 塊後;而應在 finallycatch 塊中。這應該成為標準的良好做法。通常首選使用 finally 塊,因為它在異常引發和正常到達 try 塊末尾時運行相同的代碼。如果引發了意外的異常,如 ThreadAbortException,清除代碼將不會運行。要防止泄漏,最好將所有要在 finally 中清理的非託管資源套件裝在 SafeHandle 中。注意,C# using 關鍵字可用來有效地釋放對象(包括控制代碼)。

儘管 AppDomain 回收可以清理終結器線程的資源,將清除代碼位置在正確的位置仍很重要。注意,如果線程接收到非同步異常但沒有鎖,則 CLR 嘗試自行結束線程,而不回收 AppDomain。確保儘早清理資源可使更多資源可用,也能更好地管理生存期。如果不在某一錯誤碼路徑中顯式關閉檔案的控制代碼,然後等待 SafeHandle 終結器將其清理,則下次代碼運行時,如果終結器尚未運行,訪問該檔案的嘗試就可能失敗。因此,即使不是嚴格必要的,確保清理代碼存在並能正確工作也有助於更加快速順利地從故障中恢複。

程式碼分析規則

catch 後的清理代碼應在 finally 塊中。將進行釋放的調用放置在 finally 塊中。catch 塊應以引發或再次引髮結束。可能存在異常時,例如檢測是否可以建立網路連接的代碼(這種情況下可能會出現大量異常中的任一個),任何需要在正常情況下捕捉異常的代碼都應該給出指示,說明應對代碼進行測試以驗證其是否能成功執行。

應用程式定義域之間的進程範圍的可變共用狀態應被清除,或使用受約束執列區域

如介紹所述,要以可靠的方式編寫Managed 程式碼來監視應用程式定義域之間進程範圍的共用狀態是很困難的。進程範圍共用狀態是應用程式定義域之間共用的任意資料結構,可以在 Win32 代碼中、CLR 中,也可以在使用遠端的Managed 程式碼中。任何可變共用狀態都很難在Managed 程式碼中正確編寫,任何靜態共用狀態也只能極小心地進行處理。如果具有進程範圍或電腦範圍的共用狀態,請找出某種方法來將其清除或使用受約束執列區域 (CER) 保護該共用狀態。注意,如果庫具有未被識別和糾正的共用狀態,則可能使需要清理 AppDomain 卸載的宿主(如 SQL Server)崩潰。

如果代碼使用 COM 物件,請避免在應用程式定義域之間共用該 COM 物件。

鎖在進程範圍或應用程式定義域之間不起作用。

過去,Enter 和 lock 語句(C# 參考)用於建立全域進程鎖。例如,在 AppDomain 靈活類(例如,非共用組件的 Type 執行個體、Thread 對象、暫留的字串,以及一些使用遠端在應用程式定義域之間共用的字串)上鎖定時則會這樣做。這些鎖不再是進程範圍的。若要知道是否存在進程範圍跨應用程式定義域鎖,請確定鎖中的代碼是否使用了任何持久性外部資源,如磁碟上的檔案或資料庫。

注意,如果受保護的代碼使用了外部資源,在 AppDomain 中採用鎖則可能引起問題,因為該代碼可能跨多個應用程式定義域同時運行。向一個記錄檔寫入或綁定到整個進程的通訊端時,這可能是個問題。這些更改意味著通過使用Managed 程式碼而不是使用命名的 Mutex 或 Semaphore 執行個體擷取進程全域鎖沒有簡單的方法。請建立不在兩個應用程式定義域中同步啟動並執行代碼,或使用 MutexSemaphore 類。如果不能更改現有代碼,請不要使用 Win32 命名 Mutex 來實現此同步,因為在Fiber 模式中運行意味著無法保證同一作業系統線程會擷取和釋放一個 Mutex。必須使用託管 Mutex 類或命名的 ManualResetEvent、AutoResetEventSemaphore 以 CLR 能識別的方式來同步代碼鎖,而不是使用Unmanaged 程式碼同步鎖。

避免 lock(typeof(MyType))

共用組件中僅具有一份跨所有應用程式定義域的共用代碼副本的私人和公用 Type 對象也會出現問題。對於共用組件,每個進程只有一個 Type 執行個體,這意味著多個應用程式定義域共用完全相同的 Type 執行個體。對 Type 執行個體採用鎖則會採用影響整個進程的鎖,而不僅僅影響 AppDomain。如果一個 AppDomainType 對象採用鎖,然後該線程突然中止,則鎖不會被釋放。此鎖因此可能導致其他應用程式定義域死結。

要較好地在靜態方法中採用鎖,需要向代碼添加靜態內部同步對象。如果該對象已存在,則可在類建構函式中初始化,如果不存在,則可按如下方式初始化:

複製代碼
private static Object s_InternalSyncObject;private static Object InternalSyncObject{get{if (s_InternalSyncObject == null){Object o = new Object();Interlocked.CompareExchange(ref s_InternalSyncObject, o, null);}return s_InternalSyncObject;}}

 

然後,在採用鎖時,使用 InternalSyncObject 屬性擷取要鎖定的對象。如果已在類建構函式中初始化內部同步對象,則無需使用該屬性。檢查鎖初始化代碼應類似下面的樣本:

複製代碼
public static MyClass SingletonProperty{get{if (s_SingletonProperty == null){lock(InternalSyncObject){// Do not use lock(typeof(MyClass))if (s_SingletonProperty == null){MyClass tmp = new MyClass(…);// Do all initialization before publishings_SingletonProperty = tmp;}}}return s_SingletonProperty;}}
Lock(this) 說明

通常都可對公用可訪問的單個對象採用鎖。但是,如果對象是可能導致整個子系統死結的單一執行個體對象,請考慮使用上面的設計模式。例如,對 SecurityManager 對象使用鎖可能導致 AppDomain 中發生死結,從而使整個 AppDomain 不可用。最好不要對此類型的公用可訪問的對象採用鎖。但是,單個集合或數組的鎖通常不會出現問題。

程式碼分析規則

不要對可能跨應用程式定義域使用或不能明確識別的類型採用鎖。不要對 Type、MethodInfo、PropertyInfo、String、ValueType、Thread 或任何從 MarshalByRefObject 派生的對象調用 Enter

移除 GC.KeepAlive 調用

大量現有代碼要麼在應使用 KeepAlive 時不使用,要麼在不應使用時使用。轉換為 SafeHandle 後,假定類沒有終結器而是依賴 SafeHandle 來終結作業系統控制代碼,則這些類無需調用 KeepAlive。雖然保留對 KeepAlive 的調用的效能開銷可以忽略,但如果認為對 KeepAlive 的調用是解決可能不再存在的生存期問題所必需的,或僅此即可解決這一問題,將使得代碼的維護更加困難。但是,使用 COM Interop CLR 可調用封裝 (RCW) 時,代碼仍需要 KeepAlive

程式碼分析規則

移除 KeepAlive

使用宿主保護屬性

HostProtectionAttribute (HPA) 提供聲明性安全操作來確定宿主保護要求,從而允許宿主阻止(即使是完全受信任代碼)調用不適用於給定宿主的特定方法,如 Exit 或 Show(對於 SQL Server)。

HPA 隻影響承載公用語言運行庫和實施宿主保護的非託管應用程式,例如 SQL Server。應用後,安全操作會要求建立基於類或方法所公開的宿主資源的連結。如果在用戶端應用程式中或未實施宿主保護的伺服器上運行代碼,該屬性就會“蒸發”,該屬性既不會被檢測到,因為也不會被應用到。

要點

此屬性的目的在於強制實施特定宿主的編程模型準則,而非安全行為。儘管連結要求是用於檢查與編程模型要求的一致性,但 HostProtectionAttribute 並不是一個安全許可權。

如果宿主沒有編程模型要求,則不會產生連結要求。

此屬性標識下面的內容:

  • 不適合宿主編程模型,但在其他方面良好的方法或類。

  • 不適合宿主編程模型,並可能導致伺服器託管的使用者代碼不穩定的方法或類。

  • 不適合宿主編程模型,並可能導致伺服器處理序本身不穩定的方法或類。

注意

如果要建立的類庫將由在宿主保護環境中執行的應用程式調用,應對公開 HostProtectionResource 資源類別的成員應用此屬性。具有此屬性的 .NET Framework 類庫成員僅使直接調用方被檢查。您的庫成員必須也以同樣的方式使其直接調用方得到檢查。

請在 HostProtectionAttribute 中尋找有關 HPA 的更多資訊。

程式碼分析規則

對於 SQL Server,所有用於引入同步或線程處理的方法都必須以 HPA 標識。這些方法包括共用狀態、被同步或管理外部進程的方法。影響 SQL Server 的 HostProtectionResource 值是 SharedState、Synchronization 和 ExternalProcessMgmt。但是,公開任何 HostProtectionResource 的任何方法都應由 HPA 標識,而不僅是使用影響 SQL 的資源的方法。

不要在Unmanaged 程式碼中無限期阻止

由於 CLR 不能中止線程,因此在Unmanaged 程式碼而不是Managed 程式碼中阻止可導致拒絕服務的攻擊。阻止的線程可防止 CLR 卸載 AppDomain,至少不會執行某些非常不安全的操作。使用 Win32 同步基元進行阻止是不被允許的。應儘可能避免在調用通訊端 ReadFile 時阻止 — Win32 API 最好為類似操作提供逾時機制。

任何進行本機調用的方法都最好使用具有合理有限逾時的 Win32 調用。如果允許使用者指定逾時,則不應允許使用者在沒有某種特定安全性許可權限制的條件下指定無限逾時。一般原則是,如果方法將阻止 ~10 秒以上,則需要使用支援逾時的版本或更多 CLR 支援。

這裡有一些存在問題的 API 樣本。可以建立具有逾時值的管道(匿名管道和具名管道);但代碼必須確保該管道在任何情況下都不使用 NMPWAIT_WAIT_FOREVER 調用 CreateNamedPipeWaitNamedPipe。此外,即使指定了逾時值,仍可能存在意外阻止。調用匿名管道的 WriteFile 將阻止,直到寫入所有位元組為止,這意味著緩衝區中只要存在未讀資料,WriteFile 調用就會阻止,直到讀取器釋放管道緩衝區的空間為止。通訊端應始終使用一些採用逾時機制的 API。

程式碼分析規則

在Unmanaged 程式碼中沒有逾時的阻止即是拒絕服務的攻擊。不要對 WaitForSingleObjectWaitForSingleObjectExWaitForMultipleObjectsMsgWaitForMultipleObjectsMsgWaitForMultipleObjectsEx 執行平台叫用。不要使用 NMPWAIT_WAIT_FOREVER。

識別所有依賴 STA 的功能。

識別任何使用 COM 單一執行緒 Apartment (STA) 的代碼。在 SQL Server 進程禁用 STA。依賴 CoInitialize 的功能(如效能計數器或剪貼簿)必須在 SQL Server 中禁用。

確保終結器沒有同步問題

在 .NET Framework 的未來版本中,多個終結器線程可以並存,這意味著相同類型的不同執行個體的終結器可以同時運行。它們不必完全是安全執行緒的;記憶體回收行程會保證僅有一個線程運行給定對象執行個體的終結器。但是,必須編寫終結器代碼以避免多個不同對象執行個體同時運行時出現競爭條件和死結。在終結器中使用任何外部狀態時,如向記錄檔寫入,必須處理線程處理問題。不要依賴終止來提供安全執行緒。不要使用執行緒區域儲存區(託管或本機)來儲存終結器線程的狀態。

程式碼分析規則

終結器必須沒有同步問題。不要在終結器中使用靜態可變狀態。

盡量避免使用非託管記憶體

與作業系統控制代碼一樣,非託管記憶體可能泄漏。盡量通過 stackalloc(C# 參考) 使用堆棧記憶體或通過 byte[] 使用 fixed 語句(C# 參考) 或 GCHandle 等固定託管對象。GC 最後清理這些內容。但是,如果必須分配非託管記憶體,請考慮使用從 SafeHandle 派生的類來封裝記憶體配置。

注意,至少在一種情況下 SafeHandle 不能滿足要求。對於分配或釋放記憶體的 COM 方法調用,通常是由一個 DLL 通過 CoTaskMemAlloc 分配記憶體,由另一個 DLL 使用 CoTaskMemFree 釋放該記憶體。在這些位置使用 SafeHandle 可能不合適,因為它會嘗試把非託管記憶體的生存期綁定到 SafeHandle 的生存期,而不是允許另一個 DLL 控制記憶體的生存期。

查看 Catch(Exception) 的所有用法

捕捉所有異常而不是一個特定異常的 Catch 塊現在也可捕捉非同步異常。檢查每個 catch(Exception) 塊,確保釋放所有重要的資源,並且不會跳過結束代碼,而且 catch 塊本身也不會在處理 ThreadAbortExceptionStackOverflowExceptionOutOfMemoryException 時存在不正確的行為。注意,此代碼可能會記錄和假定只能發現某些異常,或者每當發生異常時,失敗都是某個特定原因引起的。這些假定可能需要更新,以便包含 ThreadAbortException

請考慮將所有捕捉全部異常的位置更改為捕捉預計會引發的特定類型異常,如字串格式設定方法引發的 FormatException。這樣可防止在遇到意外異常時運行 catch 塊,通過捕捉意外異常,有助於確保代碼不會隱藏 bug。一般原則是,任何情況下都不要處理庫代碼中的異常(要求捕捉異常的代碼可能指示要調用的代碼中存在設計缺陷)。在某些情況下,可能需要通過捕捉一種異常來引發其他異常類型,以便提供更多資料。在這種情況下,請使用嵌套異常,將故障的實際原因儲存在新異常的 InnerException 屬性中。

程式碼分析規則

檢查Managed 程式碼中捕捉所有對象或捕捉所有異常的所有 catch 塊。在 C# 中,這意味著設定 catch {} 和 catch(Exception) {} 標誌。請考慮使異常類型非常具體,或檢查代碼以確保其在捕捉意外異常類型時不會以糟糕的方式進行。

不要假定託管線程是 Win32 線程 – 它是纖程

可以使用託管執行緒區域儲存區,但不能使用非託管執行緒區域儲存區,也不能假定代碼將在當前作業系統線程中再次運行。不要更改線程地區設定之類的設定。不要通過平台叫用來調用 InitializeCriticalSectionCreateMutex,因為它們要求進入鎖的作業系統線程也退出鎖。由於使用纖程時情況並不是這樣,因此,Win32 臨界區和 Mutex 不能直接在 SQL 中使用。注意,託管 Mutex 類不處理這些線程關聯問題。

可以安全地使用託管 Thread 對象的大部分狀態,包括託管執行緒區域儲存區和線程的目前使用者介面地區性。還可以使用 ThreadStaticAttribute,這使得現有靜態變數的值只能由當前託管線程訪問(這是在 CLR 中處理纖程本機存放區區的另一個方法)。由於編程模型的原因,在 SQL 中運行時不能更改線程的目前範圍性。

程式碼分析規則

SQL Server 以Fiber 模式運行;不要使用執行緒區域儲存區。避免對 TlsAllocTlsFreeTlsGetValueTlsSetValue. 進行平台叫用

用 SQL Server 處理類比

由於類比線上程層級運行,而 SQL 可以在Fiber 模式下運行,因此Managed 程式碼不應類比使用者,也不應調用 RevertToSelf

程式碼分析規則

讓 SQL Server 處理類比。不要使用 RevertToSelfImpersonateAnonymousTokenDdeImpersonateClientImpersonateDdeClientWindowImpersonateLoggedOnUserImpersonateNamedPipeClientImpersonateSelfRpcImpersonateClientRpcRevertToSelfRpcRevertToSelfExSetThreadToken

不要調用 Thread::Suspend

掛起線程的功能看起來是簡單操作,但可引起死結。如果持有鎖的線程由另一個線程掛起,後者又嘗試採用同一鎖,則會發生死結。Suspend 通常會對安全性、類載入、遠端和反射造成不良影響。

程式碼分析規則

不要調用 Suspend。請考慮使用真正的同步基元,如 SemaphoreManualResetEvent

用受約束執列區域和可靠性協定來保護關鍵型操作

執行更新共用狀態或需要明確完全成功或完全失敗的複雜操作時,請確保由約束執列區域 (CER) 進行保護。這樣可保證代碼在每種情況下都能運行,即使突然線程中止或突然 AppDomain 卸載。

CER 是緊跟對 PrepareConstrainedRegions 的調用的特定 try/finally 塊。

這樣做可指示Just-In-Time 編譯器在運行 try 塊之前在 finally 塊中準備所有代碼。這樣可保證產生 finally 塊中的代碼並在任何情況下都會運行。CER 中具有空 try 塊並不少見。使用 CER 可防止非同步線程中止和記憶體不足異常。有關進一步處理極深代碼的堆疊溢位的 CER 形式,請參見 ExecuteCodeWithGuaranteedCleanup。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.