Нужно ли защищать общие переменные между потоками?

45
3

Допустим, у меня есть два потока, которые читают и изменяют состояние "bool/int". Чтение и запись гарантируют, что процессор будет атомарным.

Thread 1:

if (state == ENABLED)
{
Process_Data()
}

Thread 2:

state = DISABLED

В этом случае да, поток 1 может прочитать состояние и перейти в него "если" к Process_Data, а затем Thread2 может изменить состояние. Но в этот момент это не так, чтобы продолжать обрабатывать Process_Data. Да, если мы заглянем в капот, у нас есть несогласованность состояния, которое отключено, и мы входим в функцию Process_Data. Но после его выполнения в следующий раз, когда Thread1 выполнит, он получит state = DISABLED, а не Process_Data.

Мой вопрос заключается в том, что мне все еще нужна блокировка в обоих этих потоках, чтобы сделать Thread1 check-state-and-process атомарным и Thread2 писать атомарным (wrt to Thread 1)?

спросил(а) 2014-06-17T20:19:00+04:00 5 лет, 5 месяцев назад
2
Решение
84

Вы обратились к проблемам атомарности. Однако в современных процессорах вам приходится беспокоиться не только об атомарности, но и о видимости памяти.

Например, поток 1 выполняется на одном процессоре и читает ENABLED из state - из кеша процессора.

Между тем, поток 2 выполняется на другом процессоре и записывает DISABLED, чтобы state его кеш процессора.

Без дополнительного кода - на некоторых языках, например, объявляя state изменчивым - значение DISABLED может не хватить в основной памяти в течение длительного времени. Он никогда не может быть сброшен в основную память, если поток 2 в конечном итоге изменит значение обратно в ENABLED.

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

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

ответил(а) 2014-06-17T21:30:00+04:00 5 лет, 5 месяцев назад
Еще 1 ответ
32

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

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

ответил(а) 2014-06-17T21:43:00+04:00 5 лет, 5 месяцев назад
Ваш ответ
Введите минимум 50 символов
Чтобы , пожалуйста,
Выберите тему жалобы:

Другая проблема