一、為什么要進行線程交互
在C#中,線程交互通常涉及到多個線程之間的數據共享和同步。?.
一、全局變量
在C#中,全局變量是指在程序的任何地方都可以訪問的變量。通常,全局變量是在類的外部定義的,或者在所有方法之外定義的。全局變量通常用于存儲需要在多個方法或類之間共享的數據。
1. 在類外部定義
你可以在類定義之外定義全局變量,但這通常不推薦,因為這違背了面向對象編程的原則,即封裝性。更好的做法是使用靜態成員(靜態變量)或單例模式來共享數據。
靜態變量
靜態變量屬于類,而不是類的實例。這意味著你可以通過類名直接訪問它,而不需要創建類的實例。
2. 使用單例模式
單例模式確保一個類只有一個實例,并提供一個全局訪問點。
3. 在類內部作為字段使用(非靜態)
如果你想在多個方法之間共享數據,但又不想讓這個數據成為公共的(即不想讓其他類直接訪問),可以將它定義為類的字段,并通過實例方法訪問。雖然這不是真正的“全局”訪問,因為它需要通過類的實例訪問,但它仍然可以在多個方法間共享數據。
最佳實踐和建議:
封裝性:盡量使用封裝性原則,通過屬性、方法或單例模式來控制數據的訪問。
可維護性:過度使用全局變量會使代碼難以維護和理解。盡量減少全局變量的使用,特別是在大型項目中。考慮使用依賴注入等設計模式來管理依賴和共享數據。
線程安全:當涉及到多線程時,確保全局變量的訪問是線程安全的。可以通過lock語句或者使用Concurrent集合來處理。
二、AutoResetEvent類
AutoResetEvent 是一種同步原語,它允許一個線程等待另一個線程發出信號。當一個線程調用 WaitOne() 方法時,它會被阻塞直到另一個線程調用 Set() 方法為止。每次 Set() 被調用后,AutoResetEvent 將自動重置為非信號狀態,這意味著只能喚醒一個等待的線程。
三、 ManualResetEvent類
與 AutoResetEvent 類似,ManualResetEvent 允許一個或多個線程等待某個事件的發生。不同的是,ManualResetEvent 在 Set() 被調用之后不會自動重置,除非顯式地調用了 Reset() 方法。
四、事件(Event)機制
通過事件和委托機制,可以在對象之間發送消息并通知訂閱者。這種模式非常適合需要跨多個線程進行通信的情況,尤其是在圖形用戶界面(GUI)應用中,主線程通常用于UI更新,而子線程則處理后臺任務。
五、Monitor
一、Monitor 類概述
Monitor 類位于 System.Threading 命名空間中,它允許你對對象進行鎖定(即獲取互斥鎖),從而確保在同一時刻只有一個線程可以執行被鎖定保護的代碼塊。
1. 基本鎖機制
??? Monitor.Enter 和 Monitor.Exit 用于保護臨界區,確保線程互斥訪問共享資源。
??? 與 lock 的關系:lock 關鍵字是 Monitor 的語法糖,編譯后等價于 try-finally 塊包裹的 Enter 和 Exit。
??? 何時用 Monitor:需要超時控制或非阻塞嘗試獲取鎖時(通過 TryEnter)。
2. 常用方法
??? Enter:嘗試進入臨界區并獲取鎖。
??? Exit:釋放鎖并退出臨界區。
??? TryEnter:嘗試進入臨界區并在指定時間內等待鎖。
??? Wait:釋放當前線程持有的鎖,并將該線程放入等待隊列。
??? Pulse/PulseAll:通知等待隊列中的一個或所有線程鎖已釋放,它們可以重新競爭鎖。
3. 使用場景
??? 保護共享資源:確保多個線程不會同時修改同一數據結構。
??? 生產者-消費者模式:協調生產者和消費者之間的操作。
??? 條件變量:實現基于條件的同步。
六、 Invoke和BeginInvoke
Invoke 和 BeginInvoke 在C#中主要用于跨線程操作UI控件,確保線程安全。?
Invoke和BeginInvoke的作用
?1、線程安全問題?:在Windows GUI編程中,UI元素只能在創建它們的線程上訪問。如果在一個非UI線程中直接操作UI控件,可能會導致?? 異常。Invoke和BeginInvoke方法用于在正確的線程上執行代碼,避免這種問題。
?2、同步與異步?:
?Invoke?:同步調用,當前線程會阻塞,直到委托在目標線程(通常是UI線程)上執行完畢。適用于需要確保被調用的代碼執行完成后,再繼續執行后續邏輯的場景。
?BeginInvoke?:異步調用,當前線程不會阻塞,委托會立即被加入目標線程的消息隊列,由目標線程異步執行。適用于不關心被調用代碼的執行結果,或希望避免阻塞當前線程的場景。