У меня есть concurrent_unordered_map
. Я использую функцию insert
(и никакую другую), чтобы попытаться одновременно вставить карту. Тем не менее, часто это происходит глубоко во внутренних функциях insert
. Вот некоторый код:
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
неправильно - то есть true
для value existed
, false
для value did not exist
, тогда как Стандарт определяет true
для insertion succeeded
- то есть value did not exist
. Это значительно испортило управление памятью, вызвав сбой - хотя, как именно это привело к сбою в коде unordered_map
, я не знаю. Как только я вставил правильное отрицание, оно заработало без нареканий. Это было выявлено, потому что я не проверял однопоточную версию должным образом, прежде чем перепрыгнуть через параллельный забор.