如何寫出執行緒安全的類和函式

2021-07-27 09:51:17 字數 2081 閱讀 6974

什麼是執行緒安全的類和函式,可以被多個執行緒呼叫而不會出現資料的錯亂的類和函式被叫做執行緒安全的類和函式,首先導致執行緒不安全的根本原因是我們函式中或著類中的共享成員變數(如類靜態成員變數,全域性變數),當我們的函式中或者類中有這些變數時他們都是非執行緒安全的,當有多個執行緒呼叫這些函式或者物件時,就會由於沒有對這些變數進行同步操作而產生資料錯亂。那麼什麼樣的函式和類可以被多個執行緒呼叫而不會出現資料錯亂呢。

一  無狀態的

這類函式和類不包含任何其他其他作用域中的變數活著物件,計算過程中的臨時狀態僅存在於自己的執行緒棧上的區域性變數中,並且只能有當前的執行緒訪問,不會受到其他執行緒的影響,這些無狀態的類和函式時執行緒安全的。

非執行緒安全例子:

1: 函式中引用了全域性可變變數或者物件。並且函式的執行狀態依賴該變數當前狀態的影響,此時每次的執行結果是不確定的,受到其他執行緒的影響,是非執行緒安全的。

2: 函式中引用或者返回了全域性靜態變數,區域性靜態變數,類靜態變數,因為靜態變數只會初始化一次,他的狀態會受到其他執行緒的影響。

4:呼叫了執行緒不安全的函式,那麼該函式揮著類也是非執行緒安全的。

二  可重入函式

可重入函式不會應用任何共享資料,並且函式引數也是值傳遞而非指標或者引用傳遞,他不需要任何的額外的同步操作就能保證它的執行緒安全性。這類函式成為顯式可重入函式,如果我們的指標或者引用引數沒有引用共享變數或者全域性變數也是可重入的,叫做隱式可重入函式。

一般下面的函式都是不可重入的,也不非執行緒安全的。

1: 函式內使用了靜態的資料結構(這個和上面所說的基本相同)

2: 函式體內使用了malloc和freee函式,(使用了全域性記憶體分配表)

3: 使用標準io函式(使用一些全域性的系通資源,printf使用了全域性的stdout)

三 執行緒同步

上面說的都是沒有任何同步機制情況下的執行緒安全函式,如果我們通過一些同步手段,以上的函式或者類會變成執行緒安全的函式。如果沒有同步措施,通常在單執行緒中如果我們向某個變數寫入值然後在讀值我們總能得到正確的結果或者說唯一的確定的乙個結果,但是當這些操作在不同的執行緒中執行時情況就會變的非常複雜,我們無法保證正在執行讀操作的執行緒能正確的讀到其他執行緒所做的改變,並且在沒有同步機制的環境下,編譯器或者處理器會對我們程式的執行順序進行一些調整,這些調整在單執行緒環境下不會產生影響,但是在多執行緒環境中會造成一些意想不到的結果,如果我們的執行緒之間相互影響,或者我們想讓某些執行緒按照我們的安排來執行,此時如果讓他們完全由處理器去控制,就會失去控制,此時就算沒有執行緒之間沒有共享資料也會產生錯誤,因此我們需要一些額外的手段來保證執行緒的正確執行。

通常我們通過加鎖來實現資料的同步和保護,加鎖的目的就是保證同一時刻只有乙個執行緒在操作我們所要保戶的**區的共享資料,達到資料的一致性和同步性,但是我們不能盲目的加鎖,碰到資料就加鎖,鎖是需要消耗資源的,如果我們盲目的加鎖會造成不必要的資源浪費。因此我們要仔細分析程式中的資料共享性,僅對那些共享的資料**塊加鎖即可,但是有時候加鎖也並不達到效果,當我們的鎖在乙個類中時,我們要對類的某個例項進行保護時,通常我們在成員函式中加鎖,如果我們不小心把成員變數通過成員函式的返回值或者通過成員函式乙個引用或者指標引數,把成員變數傳遞到了鎖的保護範圍之外,此時成員變數的正確性已經沒***了,因此對於鎖的使用要很小心。

如果我們想實現執行緒之間的同步,而不是讓處理器來控制線程或者程序的執行,我們可以用訊號量pv操作來實現,它允許多個執行緒在同一時刻訪問同一資源,但是需要限制在同一時刻訪問此資源的最大執行緒數目 .訊號量物件對執行緒的同步方式與前面幾種方法不同,訊號允許多個執行緒同時使用共享資源,這與作業系統中的pv操作相同。它指出了同時訪問共享資源的執行緒最大數目。它允許多個執行緒在同一時刻訪問同一資源,但是需要限制在同一時刻訪問此資源的最大執行緒數目。

下面還有兩種也會用到的方式

互斥量:採用互斥物件機制。 只有擁有互斥物件的執行緒才有訪問公共資源的許可權,因為互斥物件只有乙個,所以能保證公共資源不會同時被多個執行緒訪問。互斥不僅能實現同一應用程式的公共資源 安全共享,還能實現不同應用程式的公共資源安全共享 .互斥量比臨界區複雜。因為使用互斥不僅僅能夠在同一應用程式不同執行緒中實現資源的安全共享,而且可以在不同應用程式的執行緒之間實現對資源的安全共享。

事 件: 通過通知操作的方式來保持執行緒的同步,也可以方便實現對多個執行緒的優先順序比較的操作 .

如何寫出乙個返回多個值的c語言子函式

描述 設計乙個從5個整數中取最小數和最大數的程式 輸入輸入只有一組測試資料,為五個不大於1萬的正整數 輸出輸出兩個數,第乙個為這五個數中的最小值,第二個為這五個數中的最大值,兩個數字以空格格開。樣例輸入 1 2 3 4 5 樣例輸出 1 5 我的思路是利用三個數比大小的子函式,然後返回min,max...

如何寫乙個作用域安全的建構函式

建構函式本質上就是乙個使用new操作符呼叫的函式,使用new呼叫時,建構函式內用到的this物件會指向新建立的物件例項 function girlfriend name,age,height 使用new操作符來分配這些屬性 var girlfriend new girlfriend ying 23,...

如何在類的內部建立執行緒並安全退出

注意兩個問題 1 執行緒建立之後,很多人的寫法是直接乙個while死迴圈讓程式空轉,這樣效率低並且浪費資源 2 當類析構的時候,一定要讓執行緒正常退出。pragma once include include include include include using namespace std cl...