2016-08-25 5 views
1

У меня есть std :: map (или std :: unordered_map, как я предполагаю, они ведут себя аналогично), что я читаю и пишу. У меня также есть связанный мьютекс.Прочитайте безопасность std :: map/std :: unordered_map

Я буду читать и писать (путем вставки или удаления элементов) на карту. Я слышал, что контейнеры STL были безопасны для чтения. Если это так, безопасно использовать только мьютексы для операций записи?

Я спрашиваю, потому что мне нужно перебирать значения карты в какой-то момент, и я бы хотел использовать только мьютексы, когда элемент требует изменения.

ответ

1

Безопасно использовать мьютексы только для операций записи?

Вам необходимо убедиться, что вы не пытаетесь читать с карты во время ее написания. Таким образом, вам не нужно блокировать мьютекс, пока происходит только чтение, но если какой-либо поток может писать, все потоки (даже читатели) должны использовать мьютекс.

0

В общем, нет. И читателю, и писателю приходится приобретать мьютекс.

В противном случае вы рискуете расами данных при одновременном считывании и записи, что приводит к неопределенному поведению. На практике это может привести к сбоям, или читатели могут получить поврежденные данные, которые вы никогда не помещали на карту. Даже если он работает, он смущает полезные инструменты, такие как детекторы гонок (например, thread sanitizer, Helgrind). Это также делает ваш код потенциально не переносным.

Только если вы можете доказать, что на карте больше нет писателя, и изменения видны для всех остальных потоков, ситуация изменилась, так как теперь все обращения являются читателями. На данный момент не может быть никаких расов данных, и их можно безопасно читать с карты без какой-либо синхронизации.

Если все еще есть возможность обновлений, вы можете использовать параллельные структуры данных, чтобы избежать блокировок. C++ 11 (и C++ 17) не предоставляют один, но существуют нестандартные реализации.

Так что, если вам действительно нужна производительность, вы можете взглянуть на эти параллельных реализаций хэш-карты (в противном случае просто использовать std::unordered_map в сочетании с взаимной блокировкой для всех обращений):

  • Concurrent data structures в Intel Threading Building Блоки (TBB)
    • concurrent_unordered_map (подобные std::unorder_map, но не поддерживает одновременные операции удаления)
    • concurrent_hash_map (также поддерживает удаление Operati дополнения, но интерфейс отличается, поскольку она использует объекты аксессоры)
  • Junction (кажется, самый быстрый, но требует, чтобы потоки периодически вызывать операцию очистки, когда он не использует карту. Это делается для восстановления памяти без использования сборщика мусора, как описано в разделе «Безопасная рекультивация памяти» во введении blog post.)

 Смежные вопросы

  • Нет связанных вопросов^_^