Нужно ли защищать эту переменную с помощью блокировки? - PullRequest
8 голосов
/ 12 июля 2010

поэтому у меня логический тип в C ++ на многопроцессорной машине.Переменная запускает жизнь как true, а затем есть несколько потоков, любой из которых или более может записать ее как false.

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

Единственный способ, которым мне понадобится блокировка, - это если на очень низком уровне память может быть повреждена двумя конкурирующими операциями записи.Если, например, инструкция по сборке на процессоре A записывает 0 в байт, который представляет логическое значение, в то время как процессор B делает то же самое ... и вместо записи 0, память заканчивается значением 22 иличто-то.Это может что-то испортить.

Итак, как правило, если proc A записывает 3 в ячейку памяти, а proc B записывает 7 без синхронизации, гарантированно ли я получу по крайней мере 3 или 7?Или это так просто сломать память?

Редактировать:

Спасибо за комментарии, ребята.Немного больше информации: в программе есть синхронизация.Подводя итог, можно сказать, что рассматриваемый флаг указывает, является ли определенный пул памяти «грязным» (необходимо сжать).Следовательно, любой поток может принять решение установить этот флаг в false (что означает, что пул грязный).Например, освобождение памяти из пула делает ее грязной.Затем любой поток может также прочитать этот флаг и установить другой флаг, чтобы сигнализировать о необходимости очистки - эта проверка выполняется, когда память выделяется из пула, очистка сигнализируется, если у нас недостаточно памяти.Где-то в моем главном критическом разделе между итерациями, где каждый поток ищет дополнительные данные для обработки, я сделаю так, чтобы потоки проверили этот второй флаг и сделали что-то подходящее, чтобы убедиться, что: все остальные команды завершают свою текущую итерацию, один потокочищает память, устанавливает первый флаг обратно в значение true (поскольку пул не является грязным), устанавливает второй флаг обратно в значение false, а затем снова освобождает все потоки.

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

Я думаю, что тот же аргумент применим ко второму флагу, который я упомянул выше.

Ответы [ 6 ]

10 голосов
/ 12 июля 2010

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

Опять же, на обычном оборудовании вы можете просто пометить эту единственную логическую переменную volatile (которая была объявлена ​​бесполезной для параллельного программирования, кстати), чтобы компилятор не мог оптимизировать ее в регистр, , но только если Вы действительно не заботитесь о порядке записей.

Позвольте мне повторить это с контрольным списком:

  • Готовы ли вы потерять некоторые обновления этого логического?
  • Вы уверены, что нет других обновлений памяти, которые приходят до логического смещения в исходном коде, но могут быть переупорядочены после , что сальто может испортить ситуацию?
  • Вы уверены, что вас не волнует порядок событий в вашем приложении?

Если у вас есть три сильных ответа «да», вы могли бы сойти с рук, не защитив этот флаг. Еще подумайте о вставке получения барьера памяти перед чтением переменной и освобождении барьера памяти перед записью. Тем не менее, я предлагаю переосмыслить дизайн и четко установить синхронную связь между потоками и последовательность событий.

Надеюсь, это поможет.

8 голосов
/ 12 июля 2010

Если вы проверяете состояние переменной и устанавливаете ее в ложь в одном направлении, беспокоиться не о чем, за исключением того, что некоторые потоки могут немного опоздать, чтобы увидеть, что для переменной уже установлено значение false , (это может быть преодолено до некоторой степени с помощью ключевого слова 'volatile'.) Тогда два потока могут установить для него значение false, что не представляет проблемы, поскольку переменная установлена ​​в одно значение в одном направлении. Допустим, логическая запись в ячейку памяти не гарантированно должна быть атомарной, в чем ее вред? Окончательное значение, которое они оба напишут, будет одинаковым.

Тем не менее, вам придется использовать метод блокировки, если:

  • Значение не только однонаправленное: вы устанавливаете его в false, затем обратно в true, затем снова в false и т. Д.
  • Вы предпринимаете некоторые зависимые действия в отношении информации, для которой в потоке установлено значение false. Потому что, очевидно, может быть два победителя.
3 голосов
/ 12 июля 2010

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

У вас есть два варианта: использовать мьютекс (блокировку) или использовать атомарные примитивы. Примитивы Atomic будут использовать аппаратные инструкции для выполнения операций тестирования и настройки в поточно-ориентированном режиме, не требуя фактического мьютекса, и являются более легким решением. Компилятор GNU обеспечивает доступ к элементарным операциям через специфичные для архитектуры расширения. Есть также переносимые атомарные библиотеки операций, плавающие вокруг; библиотека Glib C предоставляет атомарные операции, которые возвращаются к использованию мьютекса, если атомарные примитивы недоступны, хотя это довольно тяжелая библиотека со многими другими функциями.

Существует библиотека Boost.Atomic , которая абстрагирует атомарные операции для C ++; Судя по его названию, похоже, что он собирается быть включенным в коллекцию библиотек Boost C ++, но еще не сделал этого.

1 голос
/ 12 июля 2010

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

В более общем плане вам, вероятно, будет проще и быстрее использовать мьютексы как обычную процедуру, чем почесать головуесли вы собираетесь уйти без одного на этот раз.Добавление того, где это не нужно, не вызывает ошибку;оставив один, где он мог бы.

1 голос
/ 12 июля 2010

Вы спрашиваете о двух вещах.

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

Вторичный запрос, который вы спрашиваете о повреждении данных из-за параллельных записей - на практике передача из ЦП в память осуществляется по шине, которая почти всегда содержитбольше битов, чем примитивных типов, над которыми вы работаете.Таким образом, такое повреждение может произойти для очень странной архитектуры или при работе с большими числами (изначально не поддерживается системой).На практике вы обычно получаете 3 или 7. Но опять же, вы не можете на это полагаться.

Чтобы заключить это - вам нужен замок.

1 голос
/ 12 июля 2010

Для bool ответ, как правило, отрицательный, мьютекс не нужен, но (как отметил Майкл Э.) все может произойти, поэтому вам, вероятно, нужно больше узнать о своей арке, прежде чем принимать такое решение. Еще одно примечание: код все еще может нуждаться в блокировке всей логики, связанной с bool, особенно если bool читается более одного раза в ходе логики подпрограммы.

Несколько отличных блогов, которые я читаю, чтобы держать меня в курсе:

http://blogs.msdn.com/b/nativeconcurrency/

http://herbsutter.com/2009/04/20/effective-concurrency-use-thread-pools-correctly-keep-tasks-short-and-nonblocking/

С наилучшими пожеланиями,

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...