2011-12-26 238 views
1

我有concurrent_unordered_map。我使用insert函數(並且沒有其他)嘗試同時插入地圖。但是,很多時候,這個函數在內部函數中崩潰很深。這裏是一些代碼:使用concurrent_unordered_map崩潰

class ModuleBase { 
public: 
    virtual Wide::Parser::AST* GetAST() = 0; 
    virtual ~ModuleBase() {} 
}; 
struct ModuleContents { 
    ModuleContents() {} 
    ModuleContents(ModuleContents&& other) 
     : access(other.access) 
     , base(std::move(other.base)) {} 
    Accessibility access; 
    std::unique_ptr<ModuleBase> base; 
}; 
class Module : public ModuleBase { 
public: 
    // Follows Single Static Assignment form. Once it's been written, do not write again. 
    Concurrency::samples::concurrent_unordered_map<Unicode::String, ModuleContents> contents; 
    Wide::Parser::AST* GetAST() { return AST; } 
    Wide::Parser::NamespaceAST* AST; 
}; 

這是我用來實際插入到地圖中的函數。有更多但它不會觸及地圖,只使用返回值insert

void CollateModule(Parser::NamespaceAST* module, Module& root, Accessibility access_level) { 
// Build the new module, then try to insert it. If it comes back as existing, then we discard. Else, it was inserted and we can process. 
Module* new_module = nullptr; 
ModuleContents m; 
{ 
    if (module->dynamic) { 
     auto dyn_mod = MakeUnique<DynamicModule>(); 
     dyn_mod->libname = module->libname->contents; 
     new_module = dyn_mod.get(); 
     m.base = std::move(dyn_mod);  
    } else { 
     auto mod = MakeUnique<Module>(); 
     new_module = mod.get(); 
     m.base = std::move(mod); 
    } 
    new_module->AST = module; 
    m.access = access_level; 
} 
auto result = root.contents.insert(std::make_pair(module->name->name, std::move(m))); 

這是根函數。它是從不同輸入上的許多線程並行調用的,但具有相同的root

void Collater::Context::operator()(Wide::Parser::NamespaceAST* input, Module& root) { 
std::for_each(input->contents.begin(), input->contents.end(), [&](Wide::Parser::AST* ptr) { 
    if (auto mod_ptr = dynamic_cast<Wide::Parser::NamespaceAST*>(ptr)) { 
     CollateModule(mod_ptr, root, Accessibility::Public); 
    } 
}); 
} 

我不完全確定wtf正在發生。我有一個共享狀態,我只能以原子方式訪問它,所以爲什麼我的代碼會死?

編輯:這實際上完全是我自己的錯。崩潰發生在insert行,我認爲這是問題 - 但它不是。它與併發無關。我測試的result返回值的走錯了路周圍 - 即truevalue existedfalsevalue did not exist,而標準定義爲trueinsertion succeeded - 即value did not exist。這大大地破壞了內存管理,導致了崩潰 - 儘管它究竟是如何導致unordered_map代碼崩潰的,我不知道。一旦我插入正確的否定,它完美無缺地工作。這是因爲我沒有在跳過併發fence之前正確測試單線程版本。

回答

1

一種可能性是,由於移動語義的問題,您正在崩潰。由空指針解引用引起的崩潰是什麼?如果您在移動對象後無意中訪問了某個對象(例如,ModuleContents),則會發生這種情況。

崩潰也可能是併發錯誤的結果。 concurrent_unordered_map在插入和檢索是原子的意義上是線程安全的。但是,無論您在裏面存儲什麼,它都不會被自動保護。因此,如果多個線程檢索相同的ModuleContents對象,它們將共享Module內的AST樹。我不確定哪些引用是可修改的,因爲我沒有看到任何const指針或引用。任何共享和可修改的東西都必須通過一些同步機制來保護(例如,鎖)。

+0

關於缺少const正確性的觀點是一個很好的觀點。但是,只有'concurrent_unordered_map'實際上是* mutable *。 – Puppy 2011-12-28 21:08:58

+0

爲什麼不添加所有你認爲是真的const修飾符,看看它是否編譯。另外,確保你沒有任何對這些const對象的可變引用。 – 2011-12-30 03:51:38

+0

我這樣做是爲了真正驗證我的假設,並且它是有效的。但是,我確實發現了實際問題。查看我的編輯解決方案。 – Puppy 2011-12-30 20:39:01