2009-10-06 3 views
31

У меня есть класс, который имеет состояние (простое перечисление), и к нему обращаются из двух потоков. Для изменения состояния я использую мьютекс (boost :: mutex). Безопасно ли проверять состояние (например, compare state_ == ESTABLISHED) или мне нужно использовать мьютекс в этом случае? Другими словами, мне нужен мьютекс, когда я просто хочу прочитать переменную, которая может быть одновременно написана другим потоком?Нужен ли мне мьютекс для чтения?

ответ

3

Да. Если thread a читает переменную, а поток b записывает ее, вы можете прочитать неопределенное значение. Операция чтения и записи не является атомарной, особенно в многопроцессорной системе.

+0

, в то время как нить писателя делает (выборка-> запись-> хранилище). Я не вижу, когда в середине те, кто читает, получают неопределенное значение, как предыдущее, так и более позднее, но никогда не определяемое. –

+0

Принимая во внимание значения перечисления, которые читаются в одной инструкции. –

+1

@Arkaitz: неопределенное, вероятно, не было правильным словом. Но архитектуры CPU/памяти становятся все более сложными с добавленными уровнями кешей, увеличенными задержками и т. Д. Ответ прост: Скажите Нет! для блокировки обмена данными. Даже эксперты совершают много ошибок в этой области. – sellibitze

0

В общем, вы не знаете, если ваша переменная объявлена ​​с «изменчивой». И ТОЛЬКО, если это единственная переменная - иначе вы должны быть очень осторожны в возможных гонках.

+0

Почему вы думаете, что нестабильные вещи? – jalf

+1

@jalf: volatile сообщает компилятору, что он не выполняет оптимизации, которые могут привести к тому, что ваш код увидит устаревшую копию переменной. –

+2

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

0

Доступ к перечислению (чтение или запись) должен быть защищен.

Другое дело: Если конфликт нити меньше, и нити принадлежат одному процессу, то критический раздел будет лучше, чем мьютекс.

8

У вас есть два потока, они обмениваются информацией, да вам нужен мьютекс, и вам, вероятно, также потребуется условное ожидание.

В вашем примере (ср. State_ == ESTABLISHED) указывает, что поток # 2 ждет потока # 1, чтобы инициировать соединение/состояние. Без мьютекса или условных выражений/событий нить # 2 должна постоянно отслеживать состояние.

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

+0

+1 для предложения условных переменных. Из его звуков он имеет поток, который должен реагировать на изменение состояния другим изменением. Если в этом случае условные переменные гораздо более приемлемы. – Falaina

+0

@Ermelli, мы все равно нуждаемся в мьютексе, если мы хотим использовать цикл ожидания занятости в любом случае (потому что цикл может делать что-то еще между тем) – Nick

0

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

wikipedia codeproject

12

Это зависит от многого.

Язык C++ ничего не говорит о потоках или атомарности.

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

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

Предполагая, что поток писателя обновляет некоторые данные, а затем устанавливает флаг целого, чтобы информировать другие потоки о том, что данные доступны, это можно изменить, чтобы флаг был установлен до, обновляя данные. Если вы не используете мьютекс или другую форму барьера памяти.

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

+0

Если вы не укажете volatile, то чтение (или запись) может * никогда не выполняться. Рано или поздно не достаточно. – EFraim

+3

Но даже с изменчивым процессором или компилятором можно переупорядочить записи, делая их бессмысленными. Правильное решение - это барьер памяти, а затем волатильность - это просто ненужная деоптимизация. – jalf

+0

@jalf: Нет, если вам нужен только один флаг. Прочтите вопрос еще раз. – EFraim

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