В потоках C ++ 11, что гарантирует std :: mutex о видимости памяти?

В настоящее время я пытаюсь изучить API потоков C ++ 11 и обнаруживаю, что различные ресурсы не предоставляют важной информации: как обрабатывается кэш процессора. Современные процессоры имеют кеш для каждого ядра (то есть разные потоки могут использовать разные кеши). Это означает, что один поток может записать значение в память, а другой поток не сможет его увидеть, даже если он увидит другие изменения, внесенные первым потоком.

Конечно, любой хороший API для создания потоков предоставляет способ решить эту проблему. Однако в API потоков C ++ не совсем понятно, как это работает. Я знаю, что std::mutex, например, каким-то образом защищает память , но не ясно, что он делает : очищает ли он весь кэш ЦП, очищает ли он только объекты, к которым обращались внутри мьютекса из кеша текущего потока, или что-то еще?

Кроме того, очевидно, что доступ только для чтения не требует мьютекса, но если поток 1 и только поток 1 непрерывно записывают в память для изменения объекта, другие потенциальные потоки не увидят устаревшую версию этого объекта что делает необходимым очищение кеша?

Атомные типы просто обходят кеш и считывают значение из основной памяти, используя одну инструкцию CPU? Делают ли они какие-либо гарантии относительно доступа к другим местам в памяти?

Как работает доступ к памяти в API потоков C ++ 11 в контексте кэшей ЦП?

Некоторые вопросы, такие как этот разговор о заборах памяти и памяти модель, но ни один источник не может объяснить это в контексте кэшей ЦП, о чем и спрашивает этот вопрос.

4 голоса | спросил john01dav 26 Mayam18 2018, 05:19:26

2 ответа


0
---- +: = 0 =: + ---- имеет ---- +: = 1 =: + ---- семантика упорядочения памяти, поэтому все в потоке A это ---- +: = 2 =: + ---- атомная запись в критическую секцию с точки зрения потока A должна быть видимой для потока B перед входом в критическую секцию в потоке B.Прочитайте http://en.cppreference.com/w/cpp/atomic/memory_order, чтобы начать.Другим хорошим ресурсом является книга C ++ Concurrency in Action .Сказав это, при использовании высокоуровневых примитивов синхронизации вы сможете избежать игнорирования большинства этих деталей, если вам не любопытно или вы не хотите испачкать руки.
ответил Preet Kukreti 26 Mayam18 2018, 05:37:56
0
Я думаю, что понимаю, к чему вы клоните.Здесь есть три вещи.Стандарт C ++ 11 описывает, что происходит на уровне языка ... блокировка ---- +: = 0 =: + ---- является операцией синхронизации.Стандарт C ++ не описывает, как это работает.Кэши ЦП не существуют в том, что касается стандарта C ++.В какой-то момент реализация C ++ помещает в ваше приложение некоторый машинный код, который реализует блокировку мьютекса.Инженеры, создающие эту реализацию, должны учитывать как спецификацию C ++ 11, так и спецификацию архитектуры.Сам процессор управляет кэшем таким образом, чтобы обеспечить семантику, необходимую для работы реализации C ++.Это может быть проще для понимания, если вы посмотрите на атомарные элементы, которые переводят в гораздо меньшие фрагменты кода ассемблера, но все же обеспечивают синхронизацию.Например, попробуйте это на GodBolt :Вы можете увидеть сборку:Таким образом, в x86 нет ничего необходимого, CPU уже обеспечивает необходимую семантику упорядочения памяти (хотя вы можете использовать явное ---- +: = 3 =: + ----, как правило, это подразумевается операциями).Это определенно не так, как он работает на всех процессорах, см. Выходная мощность:Здесь есть явные инструкции ---- +: = 5 =: + ----, потому что модель памяти Power обеспечивает меньше гарантий без них.Однако это всего лишь понижение уровня.Сам ЦП управляет совместно используемыми кэшами, используя методику, подобную протоколу MESI , которая является методикой поддержания согласованности кэша .В протоколе MESI, когда ядро ​​модифицирует блок кэша, оно должно очистить этот блок от других кэшей.Другие ядра помечают блок как недействительный, записывая содержимое в основную память при необходимости.Это неэффективно, но необходимо.По этой причине вам не нужно пытаться засунуть кучу часто используемых мьютексов или атомарных переменных в небольшую область памяти, потому что вы можете получить несколько ядер, сражающихся за один и тот же блок кэша.Статья в Википедии довольно обширна и содержит больше подробностей, чем я здесь пишу.Что-то, что я пропускаю, это то, что мьютексам обычно требуется какая-то поддержка уровня ядра, чтобы потоки могли спать или просыпаться.
ответил Dietrich Epp 26 Mayam18 2018, 06:01:46

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132