標籤:代碼區 環境 對象 不包含 標準io 局部變數 ref 靜態 detail
什麼是安全執行緒的類和函數,可以被多個線程調用而不會出現資料的錯亂的類和函數被叫做安全執行緒的類和函數,首先導致線程不安全的根本原因是我們函數中或著類中的共用成員變數(如類靜態成員變數,全域變數),當我們的函數中或者類中有這些變數時他們都是非安全執行緒的,當有多個線程調用這些函數或者對象時,就會由於沒有對這些變數進行同步操作而產生資料錯亂。那麼什麼樣的函數和類可以被多個線程調用而不會出現資料錯亂呢。
一 無狀態的
這類函數和類不包含任何其他其他範圍中的變數活著對象,計算過程中的臨時狀態僅存在於自己的線程棧上的局部變數中,並且只能有當前的線程訪問,不會受到其他線程的影響,這些無狀態的類和函數時安全執行緒的。
非安全執行緒例子:
1: 函數中引用了全域可變變數或者對象。並且函數的運行狀態依賴該變數目前狀態的影響,此時每次的運行結果是不確定的,受到其他線程的影響,是非安全執行緒的。
2: 函數中引用或者返回了全域靜態變數,局部靜態變數,類靜態變數,因為靜態變數只會初始化一次,他的狀態會受到其他線程的影響。
3: 如果一個類中含有可變的靜態變數,那麼此類也是非安全執行緒的,當我們在不同的線程中定義了該類的對象時(其實不用定義該類的對象也可),如果線上程中改變了該類的靜態成員變數,那麼也會造成資料的不一致。
4:調用了線程不安全的函數,那麼該函數揮著類也是非安全執行緒的。
二 可重新進入函數
可重新進入函數不會應用任何共用資料,並且函數參數也是值傳遞而非指標或者引用傳遞,他不需要任何的額外的同步操作就能保證它的執行緒安全性。這類函數成為顯式可重新進入函數,如果我們的指標或者引用參數沒有引用共用變數或者全域變數也是可重新進入的,叫做隱式可重新進入函數。
一般下面的函數都是不可重新進入的,也不非安全執行緒的。
1: 函數內使用了靜態資料結構(這個和上面所說的基本相同)
2: 函數體內使用了malloc和freee函數,(使用了全域記憶體配置表)
3: 使用標準io函數(使用一些全域的系通資源,printf使用了全域的stdout)
三 線程同步
上面說的都是沒有任何同步機制情況下的安全執行緒函數,如果我們通過一些同步手段,以上的函數或者類會變成安全執行緒的函數。如果沒有同步措施,通常在單線程中如果我們向某個變數寫入值然後在讀值我們總能得到正確的結果或者說唯一的確定的一個結果,但是當這些操作在不同的線程中執行時情況就會變的非常複雜,我們無法保證正在執行讀操作的線程能正確的讀到其他線程所做的改變,並且在沒有同步機制的環境下,編譯器或者處理器會對我們程式的執行順序進行一些調整,這些調整在單線程環境下不會產生影響,但是在多線程環境中會造成一些意想不到的結果,如果我們的線程之間相互影響,或者我們想讓某些線程按照我們的安排來執行,此時如果讓他們完全由處理器去控制,就會失去控制,此時就算沒有線程之間沒有共用資料也會產生錯誤,因此我們需要一些額外的手段來保證線程的正確執行。
通常我們通過加鎖來實現資料的同步和保護,加鎖的目的就是保證同一時刻只有一個線程在操作我們所要保戶的代碼區的共用資料,達到資料的一致性和同步性,但是我們不能盲目的加鎖,碰到資料就加鎖,鎖是需要消耗資源的,如果我們盲目的加鎖會造成不必要的資源浪費。因此我們要仔細剖析器中的資料共用性,僅對那些共用的資料代碼塊加鎖即可,但是有時候加鎖也並不達到效果,當我們的鎖在一個類中時,我們要對類的某個執行個體進行保護時,通常我們在成員函數中加鎖,如果我們不小心把成員變數通過成員函數的傳回值或者通過成員函數一個引用或者指標參數,把成員變數傳遞到了鎖的保護範圍之外,此時成員變數的正確性已經沒有保證了,因此對於鎖的使用要很小心。
如果我們想實現線程之間的同步,而不是讓處理器來控制線程或者進程的執行,我們可以用訊號量pv操作來實現,它允許多個線程在同一時刻訪問同一資源,但是需要限制在同一時刻訪問此資源的最大線程數目 .訊號量對象對線程的同步方式與前面幾種方法不同,訊號允許多個線程同時使用共用資源,這與作業系統中的PV操作相同。它指出了同時訪問共用資源的線程最大數目。它允許多個線程在同一時刻訪問同一資源,但是需要限制在同一時刻訪問此資源的最大線程數目。
下面還有兩種也會用到的方式
互斥量:採用互斥對象機制。 只有擁有互斥對象的線程才有訪問公用資源的許可權,因為互斥對象只有一個,所以能保證公用資源不會同時被多個線程訪問。互斥不僅能實現同一應用程式的公用資源 安全共用,還能實現不同應用程式的公用資源安全共用 .互斥量比臨界區複雜。因為使用互斥不僅僅能夠在同一應用程式不同線程中實現資源的安全共用,而且可以在不同應用程式的線程之間實現對資源的安全共用。
事 件: 通過通知操作的方式來保持線程的同步,也可以方便實現對多個線程的優先順序比較的操作。
引文連結:如何寫出安全執行緒的類和函數
[轉]如何寫出安全執行緒的類和函數