Нужна ли здесь блокировка чтения-записи? - PullRequest
0 голосов
/ 14 июля 2011

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

Вариант использования: 1) Класс, имеющий две переменные.Они доступны каждому потоку перед выполнением операции.2) Когда что-то идет не так, эти переменные обновляются, чтобы отражать сценарии ошибок.Таким образом, потоки, читающие эти переменные, могут принимать разные решения (включая прерывание)

Здесь, во втором пункте, мне нужно обновить данные.И, во-первых, каждый поток будет использовать данные.Итак, мой вопрос заключается в том, должен ли я использовать блокировку записи при обновлении данных и блокировку чтения при чтении данных.(Примечание: обе переменные находятся в памяти. Просто логический флаг и строка)

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

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

Обновление: Я сожалею, что не дал название платформы и компилятора.Я на RHEL 5.0 и использую gcc 4.6.Моя платформа x86_64.Но я не хочу, чтобы мой код зависел от конкретной ОС, потому что вскоре мы перенесем код на Solaris 10.

Ответы [ 3 ]

4 голосов
/ 15 июля 2011

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

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

Итак, давайте приведем пример:

  • Один флаг является флагом ошибки. Если ноль, вы продолжаете, в противном случае вы отменяете.
  • Другим флагом является флаг диагностического кода. Это дает точную причину ошибки.

В этом случае одним из вариантов будет следующее:

  • Чтение флага ошибки без блокировки, но с барьерами чтения памяти после чтения.
  • При возникновении ошибки возьмите блокировку, установите диагностический код и флаги ошибок, затем снимите блокировку. Если диагностический код уже установлен, немедленно снимите блокировку.

Необходимы барьеры памяти, так как в противном случае компилятор (или ЦП!) Может выбрать кеширование одного и того же результата для каждого чтения.

Конечно, если семантика ваших двух переменных различна, ответ может отличаться. Вам нужно быть более конкретным.

Обратите внимание, что точный механизм задания блокировок и барьеров памяти зависит от компилятора. C ++ 0x предоставляет переносимый механизм, но лишь немногие компиляторы полностью реализуют стандарт C ++ 0x. Пожалуйста, укажите свой компилятор и ОС для более подробного ответа.

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

0 голосов
/ 14 июля 2011

Если они являются атомарными переменными (C1x stdatomic.h или C ++ 0x atomic), то вам не нужны блокировки чтения / записи.В более ранних стандартах C / C ++ вообще не было переносимого способа использования нескольких потоков, поэтому вам нужно посмотреть, как работает используемая реализация.В большинстве реализаций типы данных, к которым можно обращаться с помощью одной машинной инструкции, являются атомарными.

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

0 голосов
/ 14 июля 2011

Таким образом, потоки, читающие эти переменные, могут принимать различные решения (включая прерывание)

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

Итак, вкратце - вам нужно , чтобы использовать блокировки чтения / записи при чтении и записи в эти общие переменные.

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

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

...