2016-04-08 18 views
0

我有以下併發哈希表:爲什麼會出現這種併發Hasmap使用升壓不行

template<typename Key, typename Value> 
class ConcurrentMap 
{ 

public: 
    ConcurrentMap() {}; 
    bool has(Key k) 
    { 
     boost::shared_lock<boost::shared_mutex> lock(schemaAccess); 
     return m.find(k) != m.end(); 
    } 

    void set(Key k, Value v) 
    { 
     boost::shared_lock<boost::shared_mutex> lock(schemaAccess); 

     // set k, v 
     if(m.find(k) != m.end()) 
     { 
      boost::upgrade_lock<boost::shared_mutex> valueLock(*valueAccess[k]); 
      boost::upgrade_to_unique_lock<boost::shared_mutex> valueUniqueLock(valueLock); 

      m.at(k) = v; 
     } 
     // insert k, v 
     else 
     { 
      lock.unlock(); 
      boost::upgrade_lock<boost::shared_mutex> schemaLock(schemaAccess); 
      boost::upgrade_to_unique_lock<boost::shared_mutex> schemaUniqueLock(schemaLock); 

      boost::shared_ptr<boost::shared_mutex> mtx = boost::make_shared<boost::shared_mutex>(); 
      valueAccess.insert(std::pair<Key, boost::shared_ptr<boost::shared_mutex> >(k, mtx)); 
      m.insert(std::pair<Key,Value>(k,v)); 
     } 
    } 

    Value get(Key k) 
    { 
     boost::shared_lock<boost::shared_mutex> lock(schemaAccess); 
     return m.at(k); 
    } 

    bool get(Key k, Value& v) 
    { 
     boost::shared_lock<boost::shared_mutex> lock(schemaAccess); 
     if(m.find(k) != m.end()){ 
      v = m.at(k); 
      return true; 
     } 
     return false; 
    } 


private: 
    std::map<Key, Value> m; 

    std::map<Key, boost::shared_ptr<boost::shared_mutex> > valueAccess; 
    boost::shared_mutex schemaAccess; 

    //http://stackoverflow.com/questions/36468270/how-to-use-a-boostmutex-as-the-mapped-type-in-stdmap/36469809?noredirect=1#comment60552035_36469809 
}; 

而下面的用法:

ConcurrentMap<int, cv::Mat> mapper; 

void worker1(){ 
    int counter = 0; 
    while(1){ 
     boost::this_thread::sleep(boost::posix_time::milliseconds(5)); 
     cv::Mat img = cv::Mat(1920,1080, CV_64F); 
     cout << "w1" << counter++ << endl; 
     mapper.set(0,img); 
    } 
} 

void worker2(){ 
    int counter = 0; 
    while(1){ 
     boost::this_thread::sleep(boost::posix_time::milliseconds(5)); 
     cout << "w2" << counter++ << endl; 
     cv::Mat img; 
     if(!mapper.get(0, img)) continue ; 
     cout << img.rows << endl; 
     cout << "done" << endl; 
    } 
} 

int main(int argc, char **argv) 
{ 
    ros::init(argc, argv, "loading_area_concat"); 


    boost::thread worker1_; 
    boost::thread worker2_; 
    worker1_ = boost::thread(worker1); 
    worker2_ = boost::thread(worker2); 

    ros::spin(); 

    return 0; 
} 

*** Error in `/home/raaj/catkin_ac2/devel/lib/loading_area/loading_area_concat': free(): invalid pointer: 0x00007fb71c000078 *** 

然而,我的代碼不斷在「得崩潰「部分在第二個線程中。如果我註釋掉「get」,它就會起作用。要麼,或者如果我完全鎖定獲取代碼與下面的以下工作:

boost::upgrade_lock<boost::shared_mutex> schemaLock(schemaAccess); 
    boost::upgrade_to_unique_lock<boost::shared_mutex> schemaUniqueLock(schemaLock); 

我似乎無法理解爲什麼發生這種情況。當我在散列圖中寫入該密鑰時,我正在鎖定它,並且當我正在閱讀它時,作者不應該進來並腐蝕內存是嗎?

回答

0

您是否嘗試鎖定get()以及檢查問題是否消失?從高級角度來看,只讀不需要鎖定,如果沒有寫入。如果有某個線程寫入該位置,則讀取也需要受到保護,否則存在競爭條件(get()可能最終使用不再有效的事物)。

好吧,我看到編輯get()中的鎖解決了這個問題,所以它似乎確實如此。

問題是,並不需要鎖定不變內存的併發讀取。但是,如果有併發寫入,讀取也需要被鎖定(針對寫入,否則會出現各種奇怪的事情,例如部分/交錯讀取等)。

+0

是的..如我上面所說..如果我叫一個完整的鎖()。在get()中它會消失。但讀取不需要被鎖定。但是,我認爲這是因爲我正在寫作而正在閱讀的地方 – Raaj

+0

Like..worker2進入閱讀模式。但是在一半的時間裏,工作者1開始寫作。但是,如果worker1開始寫入,那麼worker2將無法訪問 – Raaj

+0

有沒有辦法優雅地解決這個問題? – Raaj