2017-03-21 36 views
0

我有兩個類在同一時間在兩個線程運行,說A類和B類,A正在收集來自某些API的數據,並繼續推送更新的數據爲unordered-map作爲B->m。在相同的時間B使用數據來創建自定義類Bar,代碼是這樣的:如何確保在兩個線程中寫入相同變量線程安全的兩個類?

A

if(m.size() > 0){ 
//mtx.lock(); 
lock = B->lock; 
if(lock == false){ 
    lock = true; 
    B->m = m;  
    lock = false; 
}  
m.clear(); 
//mtx.unlock(); 
} 

B

while(true){ 
    if(m.size() > 0){ 
     //mtx.lock(); 
     if(lock == false){ 
      lock = true; 
      for (auto it : m) { 
       std::string symbol = it.first; 
       std::vector<double> v = it.second; 
       Bar b; 
       b.open = v[0]; 
       b.high = v[1];     
       bars.push_back(b); 
      } 
      m.clear(); 

      lock = false; 
     } 
     //mtx.unlock(); 
    }} 

作爲可以在這裏看到,我試過通過使用布爾值lock手動實現互斥體,當我編譯有時它有時完成賽格故障,我認爲這是因爲邊緣情況:當我在B類設置locktrue,類A剛剛跳過if(lock == false)B是讀取由真實改變A數據。我的問題是,如何避免這種情況發生?

+3

手動互斥體實現將不起作用。不要。如果C++ 1x使用來自pthread或'std :: mutex'的正確互斥對象。 – freakish

+0

@怪異的,如果我使用std :: mutex,我應該在哪裏放置mutex.lock()?請參閱上面的註釋代碼,我試過但沒有工作,因爲它是兩個類中的互斥體 –

+0

根本不要使用'mutex.lock()'。它並不是特別安全。在一段代碼中使用'std :: lock_guard'。看到我的答案。 – freakish

回答

2

手動互斥體實現不起作用(至少不是簡單的方法)。例如但從編譯點這個

lock = strategy->lock; 
if(lock == false){ 
    lock = true; 
    B->m = m;  
    lock = false; 
} 

可以rearanged到這個

lock = strategy->lock; 
if(lock == false){ 
    B->m = m; 
} 

因爲單線程的結果(這是針對編譯器默認的點,如果你不告訴它,否則)完全一樣。

還有其他原因可能會失敗,例如部分對象填充。一般情況下很複雜

因此,您必須使用您正在使用的庫提供的一些同步對象。對於C++ 11或更高,你可以簡單地使用std::mutex

#include <mutex> 
std::mutex my_mutex; 
... 

// some code 
{ 
    // lock resource 
    std::lock_guard<std::mutex> lg(my_mutex); 
    B->m = m; 
} 
// automatically releases the lock and continues the execution 
+0

我應該把lock_guard放在B班嗎?在我的代碼中,只有A寫入了m的B,B剛剛讀取了它的m,所以沒有寫入B. –

+1

@ZixuanZhang好吧,那取決於整個代碼。但是通常你在B中也需要一個lock_guard。簡單地說,因爲你最終可能會讀取一個無效的內存,因爲其他線程將會破壞底層的B-> m,同時將它設置爲一個新的值(因此讀取器的段錯誤)。 – freakish

1

您需要的std ::互斥和std :: condition_variable。

std::mutex用於保護您的代碼不受未定義的行爲和std::condition_variable通知工作者線程需要完成工作。

如果你真的想自己實現一個互斥體,然後確保你使用的是基本類型,如std::atomic_flagstd::atomic<bool>等。


實現自己「線程安全的」容器是簡單的選擇你的問題就在這裏,它會是這樣的(尚未測試,只爲尋找):

#include <mutex> 
#include <utility> 
#include <unordered_map> 

template <class Value, class Key> 
class Container { 
public: 
    bool Get(const Key &key, Value &value) { 
    std::lock_guard<std::mutex> guard(mtx_); 
    auto ite = mp_.find(key); 
    if (ite == mp_.end()) 
     return false; 

    value = std::move(ite->second); 
    mp_.erase(ite); 
    return true; 
    } 

    template <class ValueType> 
    void Insert(const Key &key, ValueType &&value) { 
    std::lock_guard<std::mutex> guard(mtx_); 
    mp_[key] = std::forward<ValueType>(value); 
    } 
private: 
    std::unordered_map<Value, Key> mp_; 
    std::mutex mtx_; 
}; 

有很多需要注意實現並行算法時的事情,我建議你閱讀一些書關注首先討論這個話題(不要擔心,無論如何你都會學習它們)。 「行動中的C++併發」是一個好的開始。

相關問題