Я должен защитить эту переменную с блокировкой?

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

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

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

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

Править:

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

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

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

8
задан Scott 13 July 2010 в 09:54
поделиться

6 ответов

Если вы проверяете состояние переменной и устанавливаете ее в false только в одном направлении, то беспокоиться особо не о чем, разве что некоторые потоки могут немного опоздать и увидеть, что переменная уже установлена в false. (Тогда два потока могут установить ее в false, что не является проблемой, поскольку переменная устанавливается в единственное значение в одном направлении. Допустим, булева запись в ячейку памяти не гарантированно атомарна, что в этом плохого? Конечное значение, которое они оба запишут, будет одинаковым.

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

  • Установка значения не является однонаправленной: вы устанавливаете его в false, затем обратно в true, затем снова в false и т.д.
  • Вы предпринимаете какое-то зависимое действие от информации о том, в каком потоке значение было установлено в false. Потому что победителей, очевидно, может быть двое.
8
ответ дан 5 December 2019 в 06:52
поделиться

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

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

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

3
ответ дан 5 December 2019 в 06:52
поделиться

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

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

Позвольте мне повторить это с помощью контрольного списка:

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

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

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

10
ответ дан 5 December 2019 в 06:52
поделиться

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

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

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

В заключение - вам нужен замок.

1
ответ дан 5 December 2019 в 06:52
поделиться

Для bool ответ обычно отрицательный, мьютекс не нужен, но (как заметил Michael E) случиться может все, что угодно, поэтому вам, вероятно, нужно больше узнать о вашей арке, прежде чем принимать такое решение. Еще одно замечание: коду все еще может понадобиться блокировка вокруг общей логики, связанной с 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/

best regards,

1
ответ дан 5 December 2019 в 06:52
поделиться

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

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

1
ответ дан 5 December 2019 в 06:52
поделиться
Другие вопросы по тегам:

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