在之前的五篇隨筆中,已經介紹了.NET 類庫中實現並行的常見方式及其基本用法,當然、這些基本用法遠遠不能覆蓋所有,也只能作為一個引子出現在這裡。以下是前五篇隨筆的目錄:
話再說回來,這五篇隨筆都屬於《同步與異步》系列。同步與異步、這是一個很大、很籠統的話題,以筆者所學很難將其將其介紹清楚,不過、筆者還是會盡力的。以下是筆者打算在近期介紹的一些知識點(大綱)、當然如果您有更好的意見或建議、歡迎評論留言。
1、與“同步與異步”相關的一些背景知識(即當前隨筆)
線程上下文、上下文切換、競爭條件(競態條件)、鎖、死鎖。
2、鎖(Lock、Monitor、ReaderWriterLockSlim)(預計1-2篇隨筆)
3、輕量級的鎖(Interlocked、SpinLock)(預計1篇隨筆)
https://msdn.microsoft.com/zh-cn/library/system.threading.spinlock(v=vs.110).aspx
https://msdn.microsoft.com/zh-cn/library/system.threading.interlocked(v=vs.110).aspx
4、WaitHandle家族 (預計2篇隨筆)
https://msdn.microsoft.com/zh-cn/library/system.threading.waithandle(VS.80).aspx
https://msdn.microsoft.com/zh-cn/library/system.threading.semaphoreslim(v=vs.110).aspx
5、警惕閉包中的變量捕獲(預計1篇隨筆)
6、線程安全的集合(預計1篇隨筆)
7、因地制宜——CPU密集型操作和IO密集型操作(預計2篇隨筆、各寫一篇)
好了,大綱暫時就先這些了,下面進入該篇隨筆的正文、線程方面的相關背景知識:
線程的強大之處、我就不再強調了。如此強大的線程、想要“免費”使用它,似乎是不可能的,就像有句話說的那樣:出來混總是要還的。
Windows中每開辟一個線程、系統都要默認分配一定量的內存空間、其中有一塊內存空間用來保存CPU寄存器中的值,我們把這個內存塊稱為線程上下文。
內存空間中除了寄存器集合之外,還有一部分叫線程棧,線程棧的內存開銷要比寄存器集合的內存開銷大的多。
線程、是程序執行流的最小單元,它就像一個邏輯CPU(或者虛擬CPU)。在系統中多個邏輯CPU(線程)共享計算機中的物理CPU核心(一個CPU可能有多個核心)。
Windows在任何時刻,都只會把一個線程分配給一個CPU核心去運行。被分配的線程運行一個“時間片”長度後,時間片到期,此時Windows會切換上下文。
每次切換上下文,Windows都會做如下操作:
1、將CPU寄存器中的值保存到當前的線程上下文中。2、從現有的線程集合中挑選一個線程。3、將挑選的線程的上下文加載到CPU寄存器中。
上下文切換完成後,CPU會運行所選線程,直到它的時間片到期,然後再次發生上下文切換。Windows大約會30毫秒切換一次線程上下文。
事實上、上下文切換對性能的影響可能超乎了你的想象:
線程在運行時,線程所需的代碼和數據都存放在CPU的高速緩存中,這使得CPU不必經常訪問內存RAM(訪問它的速度要比訪問高速緩存的速度慢的多)。
當Windows進行上下文切換後、線程運行所需的代碼和數據,可能不在CPU的高速緩存中,因此CPU必須訪問RAM來填充高速緩存、以恢復CPU的高速運行。
但是,大約30毫秒後,上下文切換再一次發生了。
另外、當一個時間片結束後,如果Widnows決定繼續運行同一個線程,那麼將不發生上下文切換。
線程也可以自主終止其時間片,節省出來的時間、CPU可以用來運行其他線程。
關於 Thread.Sleep 方法、這裡說一下它的三個特殊參數, -1, 0, 1 毫秒。
-1,當前線程將永遠休眠(此參數其實沒有意義,雖然Windows不再調度該線程,但它還是占用著內存)。
0,當前線程放棄了剩余的時間片,促使Windows發生上下文切換。當然此時Windows有可能還會繼續運行當前休眠的線程(沒有相同和更高優先級的線程需要運行的時候)
1,Sleep(0), 是不允許線程優先級較低的線程運行的, 而 Sleep(1) 會強制發生一次上下文切換。
假如有以下一行代碼、假定當時 整形變量i的值為 0 :
i = i + 1;
當有兩個線程同時運行該行代碼後,變量i的值變為了1。這時候的結果和預期的值2不一致,這時候我們認為是由於競爭條件引發了安全問題。
引發該問題的原因是:多個線程同時訪問了共享資源。
存在競爭條件的代碼,我們認為是線程不安全的代碼。
解決競爭條件的典型方案是,獲取共享資源的獨占式訪問特權,而獲取該特權的過程、我們稱之為加鎖。而這個特權、就是鎖。
但是、加鎖和釋放鎖的過程中開銷較大、性能影響較大。還有一類更好的解決方案:原子操作,我有時候也會把它稱為輕量級鎖。
當兩把鎖相互等待對方釋放的時候、我們認為此時發生了死鎖。
隨筆暫告一段落、下一篇隨筆介紹: 鎖(Lock、Monitor、ReaderWriterLockSlim)(預計1-2篇隨筆)
附,Demo : http://files.cnblogs.com/files/08shiyan/ParallelDemo.zip
參見更多:隨筆導讀:同步與異步
(未完待續...)