Boost.shared_mutex寫優先,讀共享,交叉互斥
阿新 • • 發佈:2019-01-01
shared_mutex即讀寫鎖,不同與我們常用的獨佔式鎖mutex,shared_mutex是共享與獨佔共存的鎖,實現了讀寫鎖的機制,即多個讀執行緒一個寫執行緒,通常用於對於一個共享區域的讀操作比較頻繁,而寫操作比較少的情況。
讀寫鎖比起mutex具有更高的適用性,具有更高的並行性,可以有多個執行緒同時佔用讀模式的讀寫鎖,但是隻能有一個執行緒佔用寫模式的讀寫鎖,讀寫鎖的基本規則可以總結為<寫優先,讀共享,交叉互斥>,具體表現為讀寫鎖的三種狀態:
(1)當讀寫鎖是寫加鎖狀態時,在這個鎖被解鎖之前,所有試圖對這個鎖加鎖的執行緒都會被阻塞。(交叉互斥)
(2)當讀寫鎖在讀加鎖狀態時,所有試圖以讀模式對它進行加鎖的執行緒都可以得到訪問權,但是以寫模式對它進行加鎖的執行緒將會被阻塞。(讀共享,交叉互斥)
(3)當讀寫鎖在讀模式的鎖狀態時,如果有另外的執行緒試圖以寫模式加鎖,讀寫鎖通常會阻塞隨後的讀模式鎖的請求,這樣可以避免讀模式鎖長期佔用,而等待的寫模式鎖請求則長期阻塞。(寫優先)
注:其實在讀者-寫者問題中,有讀者優先和寫者優先兩種模式,只是在boost中的shared_mutex預設的實現是寫者優先,這其實也是有道理的,因為在我們總是希望讀到的資料是最新的,這就得保證寫者優先。
下面通過一個 boost::shared_mutex的應用例項來反應其鎖機制,該例子中我們建立兩個讀者執行緒,兩個寫者執行緒,程式的實際執行結果很直接的反應了shared_mutex應用情況。
#include <boost\ref.hpp> #include <boost\thread\thread.hpp> #include <string> using namespace boost; int g_num = 10; //全域性變數,寫者改變該全域性變數,讀者讀該全域性變數 shared_mutex s_mu; //全域性shared_mutex物件 //寫執行緒 void read_(std::string &str) { const char* c = str.c_str(); while (1) { { shared_lock<shared_mutex> m(s_mu); //讀鎖定,shared_lock printf("執行緒%s進入臨界區,global_num = %d\n", c, g_num); boost::this_thread::sleep(boost::posix_time::seconds(1)); //sleep 1秒,給足夠的時間看其他執行緒是否能進入臨界區 printf("執行緒%s離開臨界區...\n", c); } boost::this_thread::sleep(boost::posix_time::seconds(1)); //讀執行緒離開後再slpp 1秒(改變這個值可以看到不一樣的效果) } } //讀執行緒 void writer_(std::string &str) { const char* c = str.c_str(); while (1) { { unique_lock<shared_mutex> m(s_mu); //寫鎖定,unique_lock ++g_num; printf("執行緒%s進入臨界區,global_num = %d\n", c, g_num); boost::this_thread::sleep(boost::posix_time::seconds(1)); //sleep 1秒,讓其他執行緒有時間進入臨界區 printf("執行緒%s離開臨界區...\n", c); } boost::this_thread::sleep(boost::posix_time::seconds(2)); //寫執行緒離開後再slpp 2秒,這裡比讀執行緒多一秒是因為如果這裡也是1秒,那兩個寫執行緒一起請求鎖時會讓讀執行緒飢餓 } } int main() { std::string r1 = "read_1"; std::string r2 = "read_2"; std::string w1 = "writer_1"; std::string w2 = "writer_2"; boost::thread_group tg; tg.create_thread(bind(read_, boost::ref(r1))); //兩個讀者 tg.create_thread(bind(read_, boost::ref(r2))); tg.create_thread(bind(writer_, boost::ref(w1))); //兩個寫者 tg.create_thread(bind(writer_, boost::ref(w2))); tg.join_all(); return 0; }
從執行結果中可以看出:
如果是讀者獲得了shared_mutex,則其他讀者可以同時進入臨界區;
如果是寫者獲得了shared_mutex,則其他的寫者或讀者都不能進入臨界區,即同時只有一個寫者能進入臨界區。