目錄
29.1 類庫和執行緒安全
29.2 基元使用者模式和核心模式構造
29.3 使用者模式構造
29.4 核心模式構造
執行緒同步:多個執行緒同時訪問共享資料時,執行緒同步能防止資料損壞。
繁瑣:在**中,必須標識出所有可能由多個執行緒同時訪問的資料。然後,必須用額外的**將這些**包圍起來,並獲取和釋放乙個執行緒同步鎖。鎖的作用是確保一次只有乙個執行緒訪問資源,只要有乙個**塊忘記用鎖包圍,資料就會損壞。鎖:會損壞效能,獲取和釋放鎖是需要時間的,因為要呼叫一些額外的方法,而且不同的cpu必須進行協調,以決定哪個執行緒先取得鎖。一次只允許乙個執行緒訪問資源。
fcl保證所有靜態方法都是執行緒安全的。
使自己的所有靜態方法都執行緒安全,使所有例項方法都非執行緒安全。
基元是指可以在**中使用的最簡單的構造。兩種基元構造:使用者模式和核心模式。
使用者模式使用特殊cpu指令來協調執行緒。意味著協調是在硬體中發生的。也意味著microsoft windows作業系統永遠檢測不到乙個執行緒在基元使用者模式的構造上阻塞了。由於使用者模式的基元構造上阻塞的執行緒永遠不認為已阻塞,所以執行緒池不會建立新執行緒來替換這種臨時阻塞的執行緒。
核心模式的構造是由windows作業系統自身提供的。所以,它們要求在應用程式的執行緒中呼叫由作業系統核心實現的函式。將執行緒從使用者模式切換為核心模式(或相反)會招致巨大的效能損失。優點:執行緒通過核心模式的構造獲取其他執行緒擁有的資源時,windows會阻塞執行緒以避免它浪費cpu時間。當資源變得可用時,windows會恢復執行緒,允許它訪問資源。
對於在乙個構造上等待的執行緒 ,如果擁有這個構造的執行緒一直不釋放它,前者就可能一直阻塞。如果是使用者模式的構造,執行緒將一直在乙個cpu上執行,我們稱為「活鎖」。如果是核心模式的構造,執行緒將一直阻塞,我們稱為「死鎖」。理想中的構造:在沒有競爭的情況下,這個構造應該快而且不會阻塞(使用者模式)。但如果存在對構造的競爭,它被作業系統核心阻塞。——混合構造
clr的許多執行緒同步構造實際只是「win32執行緒同步構造」的一些物件導向的包裝器。clr執行緒就是windows執行緒,意味著要由windows排程執行緒和控制線程同步。
原子性:一次性。非原子性:一次torn read。
兩種基元使用者模式執行緒同步構造:
易變構造:在特定的時間,它在包含乙個簡單資料型別的變數上執行原子性的讀或寫造作。
互鎖構造:在特定的時間,它在包含乙個簡單資料型別的變數上執行原子性的讀或寫操作。
29.3.1 易變構造
高階語言常規構造:if/else,swithc/case,各種迴圈,區域性變數,實參,虛方法呼叫,操作符過載等。最終,高階語言的編譯器必須將高階構造轉換成低階構造,使計算機能真正做你想做的事情。
c#編譯器將你的c#構造轉換成中間語言(il)。然後jit將il轉換成本機cpu指令,然後由cpu親自處理這些指令。此外,c#編譯器,jit編譯器,甚至cpu本身都可能優化你的**。
volatile.writer方法強迫location中的值在呼叫時寫入。此外,按照編碼那順序,之前的載入和儲存操作必須在呼叫volatile.write之前發生。
volatile.read方法強迫location中的值在呼叫時讀取。此外,按照編碼順序,之後的載入和儲存操作必須在呼叫volatile.read之後發生。
當執行緒通過共享記憶體相互通訊時,呼叫volation.write來寫入最後乙個值,呼叫volatile.read來讀取第乙個值。
29.3.2 互鎖構造
interlocked類中的每個方法都執行一次原子讀取以及寫入操作。此外,interlicked的所有方法都建立了完整的記憶體柵欄。呼叫某個interlocked方法之前的任何變數寫入都在這個interlocked方法呼叫之前執行;而這個呼叫之後的任何變數讀取都在這個呼叫之後讀取。
23.3.3 實現簡單的自旋鎖
如果需要原子性地操作類物件中的一組字段,這種情況下需要採取乙個辦法阻止所有執行緒,只允許乙個進入對欄位進行操作的**區域。可以使用interlocked的方法構造乙個執行緒同步塊。
23.3.4 interlocked anything模式
該模式類似於在修改資料庫記錄時使用的樂觀併發模式。
優點:核心模式的構造檢測到乙個資源上的競爭時,windows會阻塞輸掉的執行緒,使它不著乙個cpu「自旋「,無所謂地浪費處理器資源。
核心模式的構造可實現本機和託管執行緒相互之間的同步。
核心模式的構造可同步在用一台機器的不同程序中的執行的執行緒。
核心模式的構造可應用安全效能設定,防止未授權的賬戶訪問它們。
執行緒可一直阻塞,直到集合中的所有核心模式構造都可用,或直到集合中的任何核心模式構造可用。
在核心模式的構造上阻塞的執行緒可指定超時值;指定時間內訪問不到希望的資源,執行緒就可以解除阻塞並執行其他任務。
事件和訊號時兩種基元核心模式執行緒同步構造。
waithandle基類內部有乙個 safewaithandle欄位,它容納乙個win32核心物件控制代碼。這個欄位時在構造乙個具體waithandle派生類時初始化的。除此之外,waithandle類公開了由所有派生類繼承的方法。在衣蛾核心模式的構造上呼叫的每個方法都代表乙個完整的內柵欄。
publicabstract
class
waithandle : marshalbyrefobject, idisposable
注意:可以呼叫waithandle的waitone方法讓呼叫執行緒等待底層核心物件受到訊號。
可以呼叫waithandle的靜態waitall方法,讓呼叫執行緒等待waithandle中指定的所有核心物件都受到訊號。
可以呼叫waithandle的靜態waitany方法,讓呼叫執行緒等待waithandle中指定的所有核心物件都受到訊號。
在傳給waitany和waitall方法的陣列中,包含元素不能超過64個,否則方法會丟擲乙個system.notsupportedexception。
可以呼叫watihandle的dispose方法來關閉底層核心物件控制代碼。
不接受超時引數的那些版本的waitone和waitall方法應返回void而不是boolean。
核心模式構造的乙個常見用途就是建立在任何時刻只允許它的乙個例項執行的應用程式。
每個程序都有自己的執行緒,兩個執行緒都嘗試建立具有相同字串名稱的乙個seamphore。windows核心確保只有乙個執行緒實際地建立具有指定名稱的核心物件;建立物件的執行緒會將它creatednew變數設為true。對於第二個執行緒,windows發現具有指定名稱的核心物件已經存在了。因此,不允許第二個執行緒建立另乙個同名的核心物件。如果這個執行緒繼續執行的話,它能訪問和第乙個程序的執行緒所訪問的一樣的核心物件。不同程序中的執行緒就是這樣通過核心物件來通訊的。
29.4.1 event構造
事件其實只是由核心維護的boolean變數。事件為false,在事件上等待的執行緒就阻塞;事件為true,就解除阻塞。有兩種事件,即自動重置事件和手動重置事件。當乙個自動重置事件為true時,它只喚醒乙個阻塞的執行緒,因為在解除第乙個執行緒,因為在解除第一線程的阻塞後,核心將事件自動重置回false,造成其餘執行緒繼續阻塞。而當乙個手動重置事件為true時,它解除正在等待它的所有執行緒的阻塞,因為核心不將事件自動重置回false;
29.4.2 semaphore構造
訊號量(semaphore)其實就是由核心維護的int32變數。訊號量為0時,在訊號量上等待的執行緒會阻塞;訊號量大於0時解除阻塞。在訊號量上等待的執行緒解除阻塞時,核心自動從訊號量的計數中減1.訊號量海關聯了乙個最大int32值,當前計數決不允許超過最大計數。
多個執行緒在乙個自動重置事件上等待時,設定事件只導致乙個執行緒被解除阻塞。
多個執行緒在乙個手動重置事件上等待時,設定事件導致所有執行緒被解除阻塞。
多個執行緒在乙個訊號量上等待時,釋放訊號量導致releasecount個執行緒被解除阻塞
29.4.3 mutex構造
互斥體代表乙個互斥的鎖。
《道德經》 第二十九章
將欲取天下而為之,吾見其不得已。天下神器,不可為也,不可執也。為者敗之,執者失之。是以聖人無為,故無敗 無執,故無失。夫物或行或隨 或噓或吹 或強或羸 或載或隳。是以聖人去甚,去奢,去泰。譯文 想要治理天下,卻又要用強制的辦法,我看他不能夠達到目的。天下的人民是神聖的,不能夠違揹他們的意願和本性而加...
第二十九天
字元陣列和字元指標不是一回事 1字元陣列由若干個元素組成,每個元素中放乙個字元,而字元指標變數中存放的是位址 字串第乙個字元的位址 決不是將字串放到字元指標變數中。2賦值方法不同,對字元陣列只能對各個元素賦值,不能用以下辦法對字元陣列賦值。char str 20 str miao 字元指標變數,可以...
2018 06 04 第二十九天
class testhashset static void main string args println person println person println set int age int hashcode println person.hashcode int prime 31 boo...