[C#]C#學習筆記-多線程
C#學習筆記-多線程
羅朝輝(http://www.rzrgm.cn/kesalin/)
《C#與.NET高級程序設計》讀書筆記
1,在.NET平臺下,應用程序域和線程之間不是一一對應的,一個應用程序域可以有多個線程,而一個特定的線程在它的生命周期內不一定被限定在一個應用程序域中。Win32線程調度程序和CLR會根據需要讓線程能夠自由地跨越應用程序域的邊界,但任何特定時刻,一個線程只能運行在一個應用程序域中。System.Threading命名空間定義了與線程相關的類型。當希望訪問(正在承載當前線程的)應用程序域時,請使用Thread.GetDomain()。在任何特定時刻,一個線程也可以移動到一個特定的上下文,并有CLR重新部署在一個新的上下文中。使用Thread.CurrentContext屬性可以獲得正在執行中的線程的當前上下文。CLR控制線程移入/移出應用程序域或上下文。
2,可以使用異步委托來自動創建次線程以外處理異步方法調用。System.Threading命名空間也定義了很多用來同步訪問共享資源的類型。
3,前臺線程能阻止應用程序的終結。一直到所有的前臺線程終止后,CLR才能關閉應用程序(即卸載承載的應用程序域)。后臺線程(有時也叫守護線程)被CLR認為是程序執行中可做出犧牲的途徑,即在任何時候(即使這個線程此時正在執行某項工作)都可能被忽略。因此,如果所有的前臺線程終止,當應用程序域卸載時,所以的后臺線程也會被自動終止。
4,同步訪問共享資源的首選技術是C#的 lock 關鍵字,lock 允許定義一段線程同步的代碼語句,它需要定義一個標記(即一個對象引用),線程在進入鎖定范圍的時候必須獲得這個標記,在退出鎖定范圍時需要釋放鎖。當試圖鎖定的是一個實例級的私有方法時,使用方法本身所在對象的引用就可以了。然而,如需鎖定公共成員中的一段代碼,比較安全的做法是聲明私有的object成員作為鎖標識。如:
public class Printer
{
// 鎖標識
private object threadLock = new object();
public void PrintNumbers()
{
// 使用鎖標識
lock (threadLock)
{
...
}
}
若試圖鎖定靜態方法中的代碼,只需要聲明一個私有靜態對象成員作為鎖定標記就可以了。
5,C# lock 聲明實際上是和 System.Threading.Moniter類一同使用時的速記符號。經過編譯器的處理,鎖定區域實際上被轉化成了如下內容(可使用 ildasm.exe查看):
public void PrintNumbers()
{
Monitor.Enter(threadLock);
try
{
...
}
finally
{
Monitor.Exit(threadLock);
}
}
6,System.Threading.Interlocked 允許我們對數據進行一些原子操作:CompareExchange(), Decrement(), Exchange(), Increment()。這些靜態方法需要以引用方式傳入變量。如:注意newVal 和 intVal 的值都是遞增之后的值。
public void AddOne()
{
int newVal = Interlocked.Increment(ref intVal);
}
7,[Synchronization]特性可以有效地使對象的所以實例的成員都保持線程安全。當CLR分配帶[Synchronization]特性的對象時,它會把這個對象放在同步上下文中。這是編寫線程安全代碼的一種“偷懶”方式,因為它不需要我們實際深入線程控制敏感數據的細節,但這種方式對性能有影像,因為即使一個方法沒有使用共享資源,CLR仍然會鎖定對該方法的調用。
8,System.Threading命名空間中定義了 ThreadPool,線程池是由CLR維護的。System.Threading命名空間中還有 Timer 類型和與其相關的 TimerCallback 委托。
9,BackgroundWorker 組件:當構建一個圖形化的Windows Form桌面應用程序并且需要執行在應用程序UI線程之外的線程中長時間的任務(如調用遠程Web服務,進行數據庫事務等)時,BackgroundWorker類就很有用。該類的編程模型利用了很多結合異步委托的相同線程語法。我們只需要告訴BackgroundWorker我們希望在后臺執行哪個方法并調用RunWorkerAsync()即可。調用線程繼續運行,而工作方法會被異步執行,當工作方法執行完畢,BackgroundWorker就會通過觸發 RunWorkerCompleted 事件來通知調用線程。
浙公網安備 33010602011771號