2011-12-26 243 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