C 併發與多執行緒學習筆記(七)原子操作

2021-10-03 06:04:26 字數 1584 閱讀 7169

先來設想乙個場景:

存在乙個變數,有執行緒要讀這個變數,有執行緒要寫這個變數:

int share_value =0;

void

threadfunc()

intmain()

按理說,我們用兩個執行緒各對這個變數加10萬次,加起來應該是20萬。我們來看看結果:

再執行一次:

可以看到,兩次結果都沒有20萬。

計算結果因計算機cpu的效能而異,效能越強的cpu出現錯誤的機率更少,不排除根本不出錯的現象,在不超出int值上限的情況下提高計算量都能更明顯的差異。使用浮點數可能會有更大的誤差。

學過作業系統我們知道,系統執行執行緒是有排程的,一定存在因為排程導致的問題。我們可以使用互斥鎖來解決這個問題。修改執行緒入口函式如下:

int share_value =0;

mutex my_mutex;

void

threadfunc()

}

執行結果:

可以看到計算結果已經正確了,現在我們再修改計算量比較加鎖和不加鎖的情況。

不加鎖,計算量為2000萬:

有時候也能計算正確,但是少數。

現在為加鎖,計算量2000萬:

不論執行多少次,加鎖的操作都不會出現計算錯誤。但我們可以看到隨著計算量的**,加鎖帶來的系統開銷會成倍於計算量的增長量而變化,在面對大量的資料訪問或者很長的執行語句的時候,加鎖的弊端不得不考慮。

概念:學過作業系統我們知道,原子操作的意義即為不可分割的操作。在多執行緒程式設計中,不會被打斷的程式執行片段稱為原子操作,在執行原子操作的時候,處理機不會排程到其他執行緒,所以當執行到原子操作的時候,要麼執行直到原子操作完畢,要麼不進入原子操作。從效率上來講,原子操作比互斥鎖要更勝一籌。

用法:

std::atomic<

int> share_value =

0;

atomic是乙個類模板,傳入的模板型別即我們要對其操作的型別。原子操作的使用方式體現了它和互斥鎖不同的應用場景,互斥鎖用於幾行**的保護,原子操作用於變數的保護。

使用原子操作的方式保護資料,執行結果如下:

計算結果是正確的,雖然耗時也不少,但比使用互斥鎖要優化了許多。

C 多執行緒學習筆記七

task int task task.factory.startnew task.wait console.writeline task.result task int task task.factory.startnew var task2 task.continuewith int t cons...

C 11 併發與多執行緒學習記錄(七)

std conditon variable需要和互斥量配合工作,使用的時候需要生成該類的物件。wait函式 wait 函式傳入乙個互斥量和返回bool的可呼叫物件。如果返回true,那麼wait直接返回,否則wait解鎖互斥量並阻塞到本行,直到某個執行緒呼叫notify one為止。如果wait沒有...

多執行緒(併發)學習筆記

1,無論以哪種方式啟動乙個執行緒,要給執行緒乙個名字,對排錯 監控有幫助。2,要對執行緒interrupt做處理。3,futrure 是任務的提交者和執行者之間的通訊手段,get 會阻塞 executorservice executor executors.newsinglethreadexecut...