c++執行緒安全的map
參考了 《c++併發程式設計實戰》這本書上的程式碼寫了一個執行緒安全可以併發的map
/* * threadsafe_map.cpp * * Created on: May 11, 2018 * Author: clh01s * 執行緒安全的查詢表 * 通過boost的shared_mutex實現讀寫鎖 * 假設有一定數量的桶,每一個鍵都有一個桶 * 這就意味著可以安全地為每一個桶分配一個獨立的鎖 * 這樣一個桶就可以有1個併發N個桶就有N個併發 */ #include <iostream> #include <mutex> #include <list> #include <utility>//std::pair #include <boost/thread/shared_mutex.hpp>//boost::shared_mutex #include <vector> #include <string> #include <algorithm> // std::find_if #include <memory> #include <functional> template<typename Key,typename Value,typename Hash = std::hash<Key>> class threadsafe_lookup_table { private: class bucket_type { public: //在這個函式讀取時將鎖鎖定 Value value_for(Key const& key,Value const& default_value) const { boost::shared_lock<boost::shared_mutex> lock(_mutex); _bucket_const_iterator found_entry = find_entry_for(key); // std::cout<<"(found_entry == _data.end()) ? default_value : found_entry->second = "<<((found_entry == _data.end()) ? default_value : found_entry->second)<<std::endl; return (found_entry == _data.end()) ? default_value : found_entry->second; } //在修改時也將鎖鎖定 void add_or_update_mapping(Key const& key,Value const& value) { std::unique_lock<boost::shared_mutex> lock(_mutex); _bucket_iterator found_entry = find_entry_for(key); if(found_entry == _data.end()) { _data.push_back(_bucket_value(key,value)); } else { //如果key已經存在就更新value found_entry->second = value; } } void remove_mapping(Key const& key) { std::unique_lock<boost::shared_mutex> lock(_mutex); _bucket_iterator const found_entry = find_entry_for(key); if(found_entry != _data.end()) { _data.erase(found_entry); } } private: typedef std::pair<Key,Value> _bucket_value; typedef std::list<_bucket_value> _bucket_data; //const與非const版本的迭代器 typedef typename _bucket_data::iterator _bucket_iterator; typedef typename _bucket_data::const_iterator _bucket_const_iterator; _bucket_data _data; //每一個桶都將被一個shared_mutex例項保護 mutable boost::shared_mutex _mutex; //通過此函式確定是否有以key為關鍵字的桶可以用來存放資料 //非const版本 _bucket_iterator find_entry_for(Key const& key) { return std::find_if(_data.begin(),_data.end(), [&](_bucket_value const& item) {return item.first==key;}); } //通過此函式確定是否有以key為關鍵字的桶可以用來存放資料 //const版本 _bucket_const_iterator find_entry_for(Key const& key) const { //由於要返回非const的迭代器所以將資料放置到非const變數返回 return std::find_if(_data.begin(),_data.end(), [&](_bucket_value const& item) {return item.first==key;}); } }; public: //持有桶的變數 std::vector<std::unique_ptr<bucket_type> > buckets; Hash hasher; //獲取數量並不改變所以不需要鎖 bucket_type& get_bucket(Key const& key) const { std::size_t const bucket_index = hasher(key) % buckets.size(); std::cout<<"bucket_index = "<<bucket_index<<std::endl <<"hasher(key) = "<<hasher(key)<<std::endl <<"buckets.size() = "<<buckets.size()<<std::endl; return *buckets[bucket_index]; } public: typedef Key key_type; typedef Hash hash_type; //初始化數量,質數與雜湊效率最高所以選擇19初始化 threadsafe_lookup_table( unsigned num_buckets = 19,Hash const& hasher_ = Hash()): buckets(num_buckets),hasher(hasher_) { for(unsigned i = 0;i < num_buckets;++i) { buckets[i].reset(new bucket_type); } } threadsafe_lookup_table(threadsafe_lookup_table const& other) = delete; threadsafe_lookup_table const& operator=( threadsafe_lookup_table const& other) = delete; Value value_for(Key const& key,Value const& default_value = Value()) { return get_bucket(key).value_for(key,default_value); } void remove_maping(Key const& key) { get_bucket(key).remove_mapping(key); } }; int main() { threadsafe_lookup_table<std::string,std::string> my_map; //通過get_bucket的引數key來選擇你需要往哪個桶中存放資料 //再呼叫add_or_update_mapping來存放你的key和value my_map.get_bucket("a").add_or_update_mapping("a","aa"); //呼叫value_for來獲得key值 //你會發現value_for也需要key和value這是應為value_for的value是預設值用來確定返回的是否是真的key值如果是預設值就代表沒有查詢到 std::cout<<"key a for value ="<<my_map.get_bucket("a").value_for("a","0")<<std::endl; return 0; }
執行結果:
[email protected]:~/testcode/併發$ g++ threadsafe_map.cpp -std=c++11 -L/usr/local/lib -I/usr/local/include/boost/ -lboost_system -lboost_thread -g
[email protected]:~/testcode/併發$ ./a.out
bucket_index = 16
hasher(key) = 4993892634952068459
buckets.size() = 19
bucket_index = 16
hasher(key) = 4993892634952068459
buckets.size() = 19
key a for value =aa
相關推薦
c++執行緒安全的map
參考了 《c++併發程式設計實戰》這本書上的程式碼寫了一個執行緒安全可以併發的map/* * threadsafe_map.cpp * * Created on: May 11, 2018 * Author: clh01s * 執行緒安全的查詢
執行緒安全Map比較
如何執行緒安全的使用HashMap 2016年09月02日 13:37:32 標籤: java / hashmap / 執行緒安全 / 8116 編輯 刪除 在週二面試時,一面的面試官有問到HashMap
C++ 執行緒安全下Lock 類的兩種使用方式
“不定義,做一個保持好奇心的普通人” 꿈을 이루게 될 거예요. 2018.12.19 快三年了: Mutex 又稱互斥量,C++ 11中與 Mutex 相關的類(包括鎖型別)和函式都宣告在 <mutex> 標頭檔案中,所以如果你需要使
談C++執行緒安全容器的設計
最近看到一本書,《C++併發程式設計實戰》,[美] Anthony Williams 著,裡面有談及執行緒安全容器的設計及實現程式碼,本人覺得這樣的設計有點問題,問題還是比較明顯的,寫在這裡,供讀者自己思考吧。 關於程式碼,可以在這裡下載: https:/
[C++][執行緒安全]單例模式下雙檢查鎖和執行緒
問題 在設計模式中,有一個很經典的模式-單例模式,它可能是實現上最簡單的模式,在程式碼中也經常使用,在單執行緒下,毫無疑問延遲化載入是比較常用的,但是在多執行緒條件下,單例模式的延遲載入可能就會出現一些問題。 如以下的程式碼: T* GetInstance(
C/C++ 執行緒安全佇列
一、簡介 執行緒安全是一個比較嚴肅的問題,如果處理不好,可能導致資料被破壞,程式崩潰等問題,如何來處理多執行緒的併發問題?在windows平臺有相應的api給你用於控制併發,如互斥鎖,訊號量,事件,臨界區等,定要熟練掌握,當然現在STL庫已強大到相容不同的硬體
C++ 執行緒安全的單例模式
廢話不多說,常用的程式碼積澱下來。 一、懶漢模式 即第一次呼叫該類例項的時候才產生一個新的該類例項,並在以後僅返回此例項。 需要用鎖,來保證其執行緒安全性:原因:多個執行緒可能進入判斷是否已經存在例項的if語句,從而non thread safety。 使用double-check來
【VS開發】C++執行緒安全
我們是多麼渴望各種C++類都是多執行緒安全的,然而一旦涉及到物件間的互動,這樣的渴望可能就只能是奢望了。下面,我們以設計一個雙向鏈結點為例,看看要使其多執行緒安全將會帶來一些什麼問題。 class DoublyLinedNode{ DoublyLinedNod
C/C++程式設計教訓----函式內靜態類物件初始化非執行緒安全(C++11之前)
不少程式設計師在編寫程式的時候,會使用函式內靜態(static)變數,既能滿足函式內這個變數可以持久的記錄某些資訊,又使其訪問範圍的控制侷限於函式內。但函式內靜態類物件初始化是非執行緒安全的。 問題背景 在我們產品中對log4cxx做了一些簡單的封裝 (採用VS2005編譯),其中會
2017.10.20 C#跨執行緒操作控制元件的執行緒安全方法
C#跨執行緒操作控制元件的執行緒安全方法 在C#中,經常用到這樣一個場景,Windows Form程式啟動一個工作者執行緒執行一部分工作,這樣做是為了避免速度慢的工作如果直接呼叫會使得主Form停止響應一段時間。 既然啟動了執行緒,就避免不了執行緒之間資料傳遞的事情,相信你有很多種辦法
C++設計一個執行緒安全的懶漢單例模式
#incldue<iostream> #include<mutex> using namespace std; class CSingleton { public: static CSingleton* GetCSingleton() { if (_p ==
c/c++ 多執行緒 利用條件變數實現執行緒安全的佇列
多執行緒 利用條件變數實現執行緒安全的佇列 背景:標準STL庫的佇列queue是執行緒不安全的。 利用條件變數(Condition variable)簡單實現一個執行緒安全的佇列。 程式碼: #include <queue> #include <memory> #include
執行緒安全的Map的實現方式3種
1. HashMap,TreeMap 未進行同步考慮,是執行緒不安全的。 2. HashTable 和 ConcurrentHashMap 都是執行緒安全的。區別在於他們對加鎖的範圍不同,HashTable 對整張Hash表進行加鎖,而ConcurrentHashMap將Hash表分為16桶(s
C errno是否是執行緒安全的
本文同時發表在https://github.com/zhangyachen/zhangyachen.github.io/issues/138 在使用多執行緒時,遇到了一個問題:執行緒例程中如果需要使用errno全域性變數,如何保證errno的執行緒安全性?例如一個簡單的執行緒池程式碼: for(int i
C# 利用執行緒安全資料結構BlockingCollection實現多執行緒
using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Threading; using Danny.Infrastructure.Helper; names
C# 多執行緒之List的執行緒安全問題
網上關於List的執行緒安全問題將的很少,所以自己實驗了一把,發現確實是執行緒不安全的.所以當你在進行多執行緒程式設計中使用了共享的List集合,必須對其進行執行緒安全處理. List的Add方法是執行緒不安全的,List的原始碼中的Add方法,使用了每次噹噹前的元素達到上限,通過建立一個新的陣列例項,並給
高併發下map和chan實現的連結池的執行緒安全及效率
1.背景 上一次blog寫著寫著崩掉了,這次一定寫完一節儲存一節。 目前從事go語言的後臺開發,在叢集通訊時需要用到thrift的rpc。由於叢集間通訊非常頻繁且併發需求很高,所以只能採用連線池的形式。由於叢集規模是有限的,每個節點都需要儲存平行節點的連線,所以
C# 多執行緒呼叫靜態方法或者靜態例項中的同一個方法-方法內部的變數是執行緒安全的
C# 多執行緒呼叫靜態方法或者靜態例項中的同一個方法-方法內部的變數是執行緒安全的 using System;using System.Threading;using System.Threading.Tasks;using Sys
C++自定應執行緒安全資料結構(1)
執行緒安全的棧 該執行緒安全棧的作用是,允許多個執行緒對棧進行操作,不必再棧上進行加鎖,而是棧本身內部封裝了鎖的機制。操作的本身不是並行化的,因為不可能同時對棧既新增資料,又取出資料;其真正的意義是多個執行緒訪問時,避免上述不安全的情況發生。 #include <excep
golang執行緒安全的map
網上找的協程安全的map都是用互斥鎖或者讀寫鎖實現的,這裡用單個協程來實現下,即所有的增刪查改操作都整合到一個goroutine中,這樣肯定不會出現多執行緒併發訪問的問題。 基本思路是後臺啟動一個長期執行的goroutine,阻塞的接受自己channel中的請求req,req分為不同的請求,