Успешность записи с одновременным чтением
Если один поток в программе пытается прочитать из переменной, в то время как другой записывает в нее, значение чтения, конечно, не определено. Однако, если предположить, что есть только один писатель, запись гарантированно будет успешной? Например:
bool myGlobalVariable = false;
void thread1() {
myGlobalVariable = true;
}
void thread2() {
bool x = myGlobalVariable; //x is undefined
}
В этом случае после завершения обоих потоков myGlobalVariable
гарантированно будет true
?
Мне особенно интересно узнать о gcc в linux, но мне было бы интересно узнать, что делают другие операционные системы и компиляторы, или если ARM ведет себя не так, как x86.
2 ответа
Я не могу понять, как это может не записать значение при любых обстоятельствах, если это просто запись, а не чтение.
Причина, по которой многопоточный доступ к одной и той же переменной опасен, заключается именно в том, что не выполняется проверка того, была ли переменная изменена во время операции. Дело не в том, что он может проверить, а потом жаловаться.
Так что в случае одной записи, и просто записи (так что нет i++
, который также читается), он должен быть успешным.
Конечно, вы могли бы спроектировать аппаратное обеспечение, которое могло бы выйти из строя, если бы вы захотели, но я не вижу, как любая стандартная архитектура могла бы выйти из строя.
Как указывает Антон в своем ответе, спецификация говорит, что это неопределенное поведение, и поэтому можно было бы написать действительный компилятор C++, который преднамеренно следит за таким поведением и рандомизирует результат. Но никакой компилятор не собирается делать это на практике.
Тем не менее, никогда не стоит полагаться на поведение, которое официально не определено, поэтому, как говорится в комментарии от jeffamaphone, правильный ответ на ваш вопрос заключается в том, что запись будет успешной, но вы все равно не должны этого делать.
На практике ничего, вероятно, не получится. Тем не менее, стандарт C++11/14 довольно ясен в этом отношении. Вот цитата из черновика раздела C++14 [intro.multithread]/23
(выделение мое):
Выполнение программы содержит гонку данных, если она содержит два потенциально одновременных конфликтующих действия, по крайней мере одно из которых не является атомарным, и ни одно не происходит раньше другого, за исключением специального случая для обработчиков сигналов, описанных ниже. Любая такая гонка данных приводит к неопределенному поведению.
Где конфликтующие действия определены в [intro.multithread]/6
:
Две оценки выражений конфликтуют, если одна из них изменяет ячейку памяти (1.7), а другая обращается или изменяет ту же ячейку памяти.