C++读写锁
? ? ? ?讀寫鎖實際是一種特殊的自旋鎖,它把對共享資源的訪問者劃分成讀者和寫者,讀者只對共享資源進行讀訪問,寫者則需要對共享資源進行寫操作。
讀寫鎖實際是一種特殊的自旋鎖,它把對共享資源的訪問者劃分成讀者和寫者,讀者只對共享資源進行讀訪問,寫者則需要對共享資源進行寫操作。這種鎖相對于自旋鎖而言,能提高并發性,因為在多處理器系統中,它允許同時有多個讀者來訪問共享資源,最大可能的讀者數為實際的邏輯CPU數。寫者是排他性的,一個讀寫鎖同時只能有一個寫者或多個讀者(與CPU數相關),但不能同時既有讀者又有寫者。 在讀寫鎖保持期間也是搶占失效的。 如果讀寫鎖當前沒有讀者,也沒有寫者,那么寫者可以立刻獲得讀寫鎖,否則它必須自旋在那里,直到沒有任何寫者或讀者。如果讀寫鎖沒有寫者,那么讀者可以立即獲得該讀寫鎖,否則讀者必須自旋在那里,直到寫者釋放該讀寫鎖。 ? ? ? ? 一次只有一個線程可以占有寫模式的讀寫鎖, 但是可以有多個線程同時占有讀模式的讀寫鎖. 正是因為這個特性, 當讀寫鎖是寫加鎖狀態時, 在這個鎖被解鎖之前, 所有試圖對這個鎖加鎖的線程都會被阻塞. 當讀寫鎖在讀加鎖狀態時, 所有試圖以讀模式對它進行加鎖的線程都可以得到訪問權, 但是如果線程希望以寫模式對此鎖進行加鎖, 它必須直到所有的線程釋放鎖. 通常, 當讀寫鎖處于讀模式鎖住狀態時, 如果有另外線程試圖以寫模式加鎖, 讀寫鎖通常會阻塞隨后的讀模式鎖請求, 這樣可以避免讀模式鎖長期占用, 而等待的寫模式鎖請求長期阻塞. 讀寫鎖適合于對數據結構的讀次數比寫次數多得多的情況. 因為, 讀模式鎖定時可以共享, 以寫模式鎖住時意味著獨占, 所以讀寫鎖又叫共享-獨占鎖.
所謂「讀寫鎖」,就是同時可以被多個讀者擁有,但是只能被一個寫者擁有的鎖。而所謂「多個讀者、單個寫者」,并非指程序中只有一個寫者(線程),而是說不能有多個寫者同時去寫。
下面看一個計數器的例子。
class Counter { public:Counter() : value_(0) {}// Multiple threads/readers can read the counter's value at the same time.size_t Get() const {boost::shared_lock<boost::shared_mutex> lock(mutex_);return value_;}// Only one thread/writer can increment/write the counter's value.void Increase() {// You can also use lock_guard here.boost::unique_lock<boost::shared_mutex> lock(mutex_);value_++;}// Only one thread/writer can reset/write the counter's value.void Reset() {boost::unique_lock<boost::shared_mutex> lock(mutex_);value_ = 0;}private:mutable boost::shared_mutex mutex_;size_t value_; };shared_mutex?比一般的?mutex?多了函數?lock_shared() / unlock_shared()?,允許多個(讀者)線程同時加鎖、解鎖,而?shared_lock?則相當于共享版的?lock_guard?。
對?shared_mutex?使用?lock_guard?或?unique_lock?就達到了寫者獨占的目的。
測試代碼:
boost::mutex g_io_mutex;void Worker(Counter& counter) {for (int i = 0; i < 3; ++i) {counter.Increase();size_t value = counter.Get();boost::lock_guard<boost::mutex> lock(g_io_mutex);std::cout << boost::this_thread::get_id() << ' ' << value << std::endl;} }int main() {Counter counter;boost::thread_group threads;threads.create_thread(boost::bind(Worker, boost::ref(counter)));threads.create_thread(boost::bind(Worker, boost::ref(counter)));threads.join_all();return 0; }輸出(仍然是隨機性的):
當然,對于計數器來說,原子類型?boost::atomic<>?也許是更好的選擇。
假如一個線程,先作為讀者用?shared_lock?加鎖,讀完后突然又想變成寫者,該怎么辦?
方法一:先解讀者鎖,再加寫者鎖。這種做法的問題是,一解一加之間,其他寫者說不定已經介入并修改了數據,那么當前線程作為讀者時所持有的狀態(比如指針、迭代器)也就不再有效。
方法二:用?upgrade_lock?,它可以當做?shared_lock?用,但是必要時可以直接從讀者「升級」為寫者。
{// Acquire shared ownership to read.boost::upgrade_lock<boost::shared_mutex> upgrade_lock(shared_mutex_);// Read...// Upgrade to exclusive ownership to write.boost::upgrade_to_unique_lock<boost::shared_mutex> unique_lock(upgrade_lock);// Write... }可惜的是,我沒能給?upgrade_lock?找到一個頗具實際意義的例子。
創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎
總結
- 上一篇: JanusGraph 安装
- 下一篇: spark 提交至yarn异常超时 Cl