Unordered_map безопасность потоков
Я меняю одну программу потока на несколько потоков, используя boost: thread library. Программа использует unordered_map как hasp_map для поиска. Мой вопрос...
В свое время многие потоки будут писать, а в другом - чтение, но не одновременно чтение и запись, то есть либо все потоки будут читаться, либо все будет писать. Будет ли это потокобезопасным и контейнер предназначен для этого? И если это будет, будет ли это действительно одновременным и улучшать производительность? Нужно ли использовать какой-либо механизм блокировки?
Я где-то читал, что С++ Standard говорит, что поведение будет undefined, но это все?
UPDATE: Я также думал о Intel concurrent_hash_map. Будет ли это хорошим вариантом?
Ответы
Ответ 1
Контейнеры STL спроектированы таким образом, что вы гарантированно сможете:
а. Одновременное чтение нескольких потоков
или
В. Один поток, записывающий в то же время
Наличие нескольких потоков записи не является одним из указанных выше условий и не допускается. Таким образом, при написании нескольких потоков создается расчёт данных, который является undefined.
Вы можете использовать мьютекс, чтобы исправить это. Совместное использование shared_mutex (в сочетании с shared_locks) было бы особенно полезно, поскольку этот тип мьютекса допускает множественные параллельные считыватели.
http://eel.is/c++draft/res.on.data.races#3 является частью стандарта, который гарантирует возможность одновременного использования функций const для разных потоков. http://eel.is/c++draft/container.requirements.dataraces указывает некоторые дополнительные неконстантные операции, которые безопасны для разных потоков.
Ответ 2
Будет ли это быть потокобезопасным и контейнер, предназначенный для этого?
Нет, стандартные контейнеры не являются потокобезопасными.
Нужно ли использовать какой-либо механизм блокировки?
Да, да. Поскольку вы используете boost, boost::mutex
будет хорошей идеей; в С++ 11, там std::mutex
.
Я где-то читал, что С++ Standard говорит, что поведение будет undefined, но это все?
Действительно, поведение undefined. Я не уверен, что вы подразумеваете под словом "это все?", Так как поведение undefined - худшее возможное поведение, а программа, которая показывает его, по определению неверна. В частности, некорректная синхронизация потоков может привести к случайным сбоям и повреждению данных, часто таким образом, что их очень трудно диагностировать, поэтому было бы разумно избежать любой ценой.
UPDATE: Я также думал о Intel concurrent_hash_map. Будет ли это хорошим вариантом?
Звучит неплохо, но я никогда не использовал его сам, поэтому я не могу предложить свое мнение.
Ответ 3
Существующие ответы охватывают основные моменты:
- у вас должен быть замок для чтения или записи на карту.
- вы можете использовать блокировку с несколькими считывателями/одиночными писателями для улучшения concurrency
Кроме того, вы должны знать, что:
-
используя ранее полученный итератор, или ссылку или указатель на элемент на карте, считается операцией чтения или записи
Операции записи -
выполняемые в других потоках, могут привести к недействительности указателей/ссылок/итераторов на карте, как если бы они были выполнены в одном и том же потоке, даже если блокировка снова будет получена до того, как будет предпринята попытка продолжить используя их...
Ответ 4
Вы можете использовать concurrent_hash_map или использовать мьютекс при доступе к unordered_map. один из вопросов об использовании intel concurrent_hash_map - вам нужно включить TBB, но вы уже используете boost.thread. Эти два компонента имеют перекрывающиеся функциональные возможности и, следовательно, усложняют базу кода.
Ответ 5
std:: unordered_map отвечает требованиям Container (ref http://en.cppreference.com/w/cpp/container/unordered_map). Для безопасности контейнерных потоков см. http://en.cppreference.com/w/cpp/container#Thread_safety.
Важные моменты:
- "Различные элементы в одном контейнере могут быть изменены одновременно разными потоками"
- "Все функции-члены-члены могут быть вызваны одновременно разными потоками в одном контейнере. Кроме того, функции-члены begin(), end(), rbegin(), rend(), front(), back(), data(), find(), lower_bound(), upper_bound(), equal_range(), at() и, за исключением ассоциативных контейнеров, оператор [], ведут себя как const для целей безопасности потоков (то есть они могут также вызывается одновременно разными потоками в одном контейнере).