Скажем, у меня есть инициализированный, но пустой std::unordered_map и два одновременных потока, которые будут его заполнять. Два потока будут только записывать на карту, и ничего не будет считываться с карты, пока два потока не закончат работу.
Кроме того, два потока никогда не будут работать с одними и теми же ключами на карте. Например, скажем, поток 1 будет заполнять ключи от «A» до «M», а поток 2 будет одновременно заполнять ключи от «N» до «Z».
Эта ветка безопасна?
В моей текущей реализации у меня есть 8 потоков, записывающих в один мьютексированный std::unordered_map способом, описанным выше. Мьютекс явно замедляет процесс (заполняется около 10 000 ключей), поэтому мне интересно, нужен ли мне вообще мьютекс.
Спасибо всем!
Почитайте std::unordered_map::merge. Два потока могут заполнить две разные карты, а затем их можно объединить.
@ÖöTiib Для этого требуется C++17. Q помечен как C++11





Нет, это не потокобезопасно. Класс std::unordered_map не предоставляет никаких специальных гарантий потокобезопасности, только тот же самый обычный уровень потокобезопасности, который по умолчанию обеспечивают все стандартные классы. Это означает, что для одного потока небезопасно каким-либо образом обращаться к структуре, в то время как другой поток изменяет или может изменять ее.
IRC, существуют некоторые дополнительные гарантии для классов std в отношении методов const, но в данном случае они не актуальны. Один простой способ, которым это может сломаться, - это если вставка нового значения вызывает перехеширование, в то время как другой поток находится в середине вставки другого значения.
@ДэнМ. Все функции const являются считывателями, так что все в порядке, если это все, что вы делаете. Как только вы добавите писателя в микс, все ставки сняты
@ДэнМ. Я не люблю рассуждать о том, как это может сломаться, потому что это приводит к (к сожалению, очень распространенному) заблуждению, что если вы не можете придумать, как это может сломаться, и это работает, когда вы пытаетесь это сделать, то безопасно делать.
@ Натан Оливер, нет, не совсем. Функции const могут все. Нет никакой гарантии, что они будут потокобезопасными. Но STL предоставляет такую гарантию.
@ДэнМ. Я имел в виду в контексте STL.
@DavidSchwartz Я не предполагаю. Я утверждаю это как реальный сценарий, демонстрирующий, как он нарушает потокобезопасность, даже если «все потоки действуют на разные ключи», чтобы подчеркнуть, что это не потокобезопасно.
@ДэнМ. Но проблема в том, что если у ОП есть другой (но похожий) вопрос, а затем он делает вывод: «Я не понимаю, как это может пойти не так; это должно быть безопасно», они будут введены в заблуждение.
@MartinBonner чем введен в заблуждение? «Нет, это небезопасно. Вот один из многих способов, которыми он может сломаться» как вводит в заблуждение? Я бы сказал, что без этого примера OP может быть введен в заблуждение (и уже почти был) «Но у меня есть очень конкретные варианты использования, которые наверняка будут потокобезопасными!», Нет, это не так, и вот почему.
@ДэнМ. Это прекрасный пример того, как можно ввести человека в заблуждение. То, что вы можете придумать, как это может привести к сбою, - это НЕТ, почему его очень конкретный вариант использования не является потокобезопасным. Его очень специфический вариант использования не является потокобезопасным, поскольку об этом говорится в соответствующих стандартах. Даже случаи, когда никто не может придумать, как это может привести к сбою, не являются потокобезопасными. К сожалению, это очень распространенное заблуждение, которое на протяжении многих лет приводило к огромному количеству боли и страданий.
Я не могу сказать вам, сколько раз, обычно в комментариях на этом самом веб-сайте, люди утверждали, что все безопасно, а я настаивал, что это не так. Затем кто-то (иногда я, а что-то иное) объяснил, как он может выйти из строя, и они сказали: «О, теперь понятно. Это небезопасно». Это худший возможный урок, который они могут усвоить, настраивая их на провал, как только они полагаются на что-то, режимы отказа которых они недостаточно умны, чтобы предвидеть. Черт возьми, когда-то мысль о том, что ЦП будет выполнять запись вне порядка программы, была непредвиденной.
Вот почему я хотел спросить вместо локального тестирования ... не уверен, что мои простые тесты будут A) работать единогласно и B) масштабироваться до моей полной реализации. Учитывая всю эту информацию, я просто оставлю мьютекс. Спасибо всем!
@DavidSchwartz, вот что я сказал. Я никогда не оспаривал конкретный вариант использования, я добавил к исходному вопросу более подробное объяснение. Потому что исходный вопрос был построен так. Является ли потокобезопасным? Нет. Даже если я сделаю только Б? Да, даже если вы делаете только Б, вот почему. Ваша логика в конечном счете ошибочна. Я мог бы утверждать то же самое: поскольку пользователь будет получать только ответы «да/нет» без каких-либо объяснений, он никогда не научится думать/предвидеть себя. С другой стороны, очень важна способность оспаривать их идеи и быстро находить контрпримеры.
@ДэнМ. Чего вы, кажется, не понимаете, так это того, что этот особый навык предвидения для себя не только бесполезен, но и определенно вреден. В большинстве случаев вы можете предвидеть, как он может сломаться. Но это так же неправильно, даже когда вы не можете предвидеть, как он может сломаться, на самом деле, тогда это гораздо вреднее. Таким образом, развитие навыка видеть, как он может сломаться, вводит вас в заблуждение и заставляет думать, что в менее распространенном случае, когда вы не можете предвидеть, как он может сломаться, вы в безопасности. Вот почему я упорно работаю над тем, чтобы не склонять людей к такому образу мышления. Это приводит только к ошибкам.
Я видел похожие вопросы. Если важна производительность, рассмотрите другую структуру данных. Возможно, иметь unordered_map для каждого потока было бы лучше, если бы они не пересекались по ключам.