多線程編程總結:一、認識多線程本質

       在當今計算機系統中,已經大量存在多核心CPU,或者是在多核心基礎上有進一步的超線程技術將虛擬CPU數量翻倍。在計算機發展之初,我們的應用程序是按照一個CPU只做一件事情來應用,也就是順序執行。隨着時間的不斷變化,我們的CPU計算能力越加強大,那麼我們可以使用線程技術,讓每個核心都去做一件事,或者使用時間切片(time slicing)技術,讓我們的CPU在各個線程中切換以同時達到一種處理多個線程任務的目標。可以同時聽歌,看文檔,運行時鐘,掛遊戲。

       需要注意的是,對於時間分片技術,我們實際上是同一個核心將一個線程的運行1個時間片(time slice)的時間,然後保存狀態,切換到另外一個線程去,這種切換動作被稱爲上下文切換。表現出來是並行運算。但是我們需要考慮到CPU不斷地切換線程,實際上也會有代價,需要保存上一個線程狀態,切換到下一個線程去。如果線程數目過多的情況下,就會消耗大量時間在切換線程上。這就是爲什麼多線程不一定會讓程序更快,而需要綜合衡量。

 

       多線程併發問題:缺乏原子性、競態條件、複雜的內存模型和死鎖。

一、缺乏原子性

       首先原子操作的定義是:一個原子內代碼,要麼處於沒有操作,要麼已經操作完畢,而不存在“操作中”這個中間態。核心是它是整體的,不可分割。如果我們的多線程代碼如果不是原子性的,那麼這種情況下它就缺乏原子性。

 

二、競態條件

       競態條件是值得我們同時開啓的多個線程,它的執行順序是根據系統判斷哪個線程競爭勝利,先執行到一部分,然後發生上下文切換到另外一個另外一個線程去。而至於哪個線程在競爭中勝出不可預知,就算99.99%的時間具有正確行爲,那麼也有0.01%會出現另外一個線程競爭勝利。

 

三、複雜的內存模型

      現在我們的CPU不會每次運行某個變量的時候都會去內存取出操作,而是將這個變量緩存在CPU的高速緩存中,這個緩存會定時和主內存進行同步。意味着在多核心CPU中處理不同線程時,我們的線程處理的是各自CPU核心的高速緩存中的變量,實際上是2個不同的變量。那麼當我們多線程對該變量進行更新時就不是準確的。

 

四、鎖定造成死鎖

       C#中使用Lock語句或者Monitor.Enter() Monitor.Exit()將一段代碼作爲原子操作,對Lock住的該對象,系統會判斷只允許一個線程訪問該段Lock住代碼,其他線程掛起等待。如果被Lock住的對象發生改變,其他線程訪問過來的時候,系統會認爲不是同一段Lock代碼,就會允許那個代碼訪問,這就是Lock失效了。 

        鎖本身也會出問題,例如此處有2個線程分別是A和B線程, 同時有2個鎖分別是C和D,那麼A線程在C鎖獲得之後請求D鎖,而B線程在獲得D鎖之後請求C鎖,就會造成互相等待對方釋放,這就是死鎖的由來。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章