C 多執行緒(二) 資料同步

2021-07-22 10:33:21 字數 2941 閱讀 4144

資料同步是多執行緒程式設計中不可避免的話題,下面來**一下資料同步相關的知識點。

互斥量:互斥量是一種可被鎖定的變數,互斥量一般有排他互斥量、共享互斥量以及迴圈互斥量。排他互斥量是一種只能被乙個執行緒訪問(鎖定)的互斥量,當乙個執行緒獲得排他互斥量的鎖後,其他執行緒只有在該互斥的鎖釋放後才能獲得這個互斥量的鎖;共享互斥量一般實現為讀共享、寫排他的互斥量,換句話說就是該互斥量的讀鎖可以被多個執行緒獲取(因為讀並不會改變資料),而寫鎖只能被乙個執行緒獲取; 迴圈互斥量本質也是一種排他互斥量,所不同的是,迴圈互斥量被乙個執行緒獲得其鎖後,該執行緒可以多次鎖定該互斥量,當然,最後在釋放該互斥量時,有多少次鎖定,就應該釋放多少次。c++11標準庫中提供了排他互斥量和迴圈互斥量以及其他特定功能的互斥量,基礎的排他互斥量和迴圈互斥量分別是std::mutex和std::recursive_mutex,可惜的是,c++標準委員會在經過商討後,決定不在c++11中提供共享互斥量。但這個互斥量在boost庫中是受到支援的。

鎖:出於方便使用和安全的目的,對互斥量進行了封裝,這就是鎖。c++11提供了簡單的鎖std::lock_guard和靈活的鎖std::unique_lock。

mutex,使用時非常簡單,例程如下:

#include #include #include std::mutex wrmutex;

int total = 0;

void test(bool flag)

}int main()

單純地使用std::mutex,這時可能會有潛在的安全隱患——當忘記呼叫unlock()或者unlock()呼叫與lock()呼叫不對稱時,這時就可能發生死鎖或者未定義的錯誤。由於這種安全隱患的存在,再加上raii的設計思想,lock_guard就相應地出現了。lock_guard的使用例程如下:

#include #include #include std::listsome_list;

std::mutex some_mutex;

void add_to_list(int new_value)

bool list_contains(int value_to_find)

lock_guard是乙個模板類,它模板引數是互斥量型別,同時還要傳進乙個相應的互斥量例項。lock_guard在建構函式中鎖定互斥量,在析構函式中釋放互斥量,因此使用lock_guard後,互斥量不需要顯式地鎖定或者釋放。

unique_lock是一種相當靈活的鎖,它也是乙個模板類,模板引數為互斥量型別,初始化時也需要傳入乙個互斥量的例項。為了詳細地了解unique_lock,我們首先從其建構函式開始。

(1)

unique_lock() noexcept;

(2)explicit unique_lock (mutex_type& m);

(3)unique_lock (mutex_type& m, try_to_lock_t tag);

(4)unique_lock (mutex_type& m, defer_lock_t tag) noexcept;

(5)unique_lock (mutex_type& m, adopt_lock_t tag);

template unique_lock (mutex_type& m, const chrono::duration& rel_time);

template unique_lock (mutex_type& m, const chrono::time_point& abs_time);

copy [deleted]

unique_lock (const unique_lock&) = delete;

move

unique_lock (unique_lock&& x);

我們主要關注第(2)(3)(4)(5)建構函式。

(2)建構函式需要傳入乙個互斥量例項,這時使用unique_lock和lock_guard的效果是一樣的;

(3)(4)(5)建構函式的不同,主要表現在傳入的tag引數的值不同。

tag的可選值如下:

try_to_lock:嘗試獲得互斥量的鎖

defer_lock:延遲鎖定(在以後手動鎖定)

adopt_lock:接收乙個互斥量(這個互斥量已經在外部被加鎖)

無論使用何種tag,還是傳入的是排他互斥量或者迴圈互斥量,只要構造時是正確的,unique_lock物件就能夠在析構時正常釋放其鎖。

unique_lock主要成員函式:

這些成員函式簡單易懂,無需多說。

迴圈互斥量是一種可以連續鎖定的互斥量,當資料的同步需要多重驗證時,這時迴圈互斥量就會相當有用。簡單的例程如下:

void test2()

std::timed_mutex類似於std::mutex,所不同的是,timed_mutex有了時間控制功能,其增加的兩個函式是:

try_lock_for(chrono::duration& rel_time)

try_lock_until(const const chrono::time_point& abs_timerel_time)

try_lock_for函式將等待最長rel_time的時間,在這個時間段內嘗試獲得鎖,否則獲取鎖失敗,不繼續等待,執行緒繼續執行。

trye_lock_for函式將等待最遲到abs_timerel_time這個時間點,在這個時間點前嘗試獲得鎖,否則獲取鎖失敗,不繼續等待,執行緒繼續執行。

std::recursive_timed_mutex是timed_mutex相應的加強版,在此不再贅述。

C 多執行緒同步 二 Mutex

monitor和lock多用於鎖定被呼叫端,而mutex則多用鎖定呼叫端。lock this 或者是用monitor也是一樣的,如下 monitor.enter this do something monitor.exit this monitor的好處是可以用tryenter this,timeo...

C 多執行緒同步

在開發中經常會遇到執行緒的例子,如果某個後台操作比較費時間,我們就可以啟動乙個執行緒去執行那個費時的操作,同時程式繼續執行。在某些情況下可能會出現多個執行緒的同步協同的問題,下面的例子就展示了在兩個執行緒之間如何協同工作。這個程式的思路是共同做一件事情 從乙個arraylist中刪除元素 如果執行完...

多執行緒同步技術 二

5.semaphore semaphore是同一時間允許幾個程序同時獲取共享資源的,如下例 新建立了6個執行緒,設定最多只有2個執行緒,每次只有2個執行緒可以獲取資源,等到這個兩個執行緒執行完畢,釋放了執行緒鎖,然後餘下的執行緒可以繼續獲取鎖執行 6.autoresetevent manualres...