Рассмотрим эту функцию:
void foo(int * p)
{
// something
}
Может ли компилятор предположить, что никакой другой поток не изменит значение, указанное p? Или оно должно действовать так, как если бы это значение можно было изменить в любой момент?
void bar(volatile int * p)
{
}
Если это не так, делает ли volatile
ключевое слово помогает? ПОЛУЧИЛ № 69 говорится, что volatile
Ключевое слово в большинстве случаев всегда игнорируется компиляторами.
РЕДАКТИРОВАТЬ:
По-видимому, существует некоторое недопонимание фразы «предполагает компилятор». Позвольте мне уточнить это:
*p
в реестре при первом чтении используйте его, пока p не выйдет из области видимости. В этот момент следует записать значение *p
по этому адресу памяти. *p
читается, компилятор должен извлечь его значение из памяти так как есть вероятность, что другой поток изменил его. Каждый раз *p
изменено, компилятор должен записать его в память, чтобы другие потоки могли его прочитатьКомпилятор не может сделать такое предположение, как и программист. Одно только ключевое слово volatile не защитит от одновременного доступа.
Компилятор может предположить, что никакой другой поток не изменит значение, на которое указывает p
Это означает, что вы должны убедиться, что ваш код не зависит от этого, или что у него есть соответствующие механизмы синхронизации, чтобы избежать состояния гонки. Другими словами, компилятор делает предположение, и это предположение может быть неверным.
volatile
Ключевое слово здесь мало релевантно.
Правило таково: если один поток выполняет запись в местоположение данных в то же время, когда другой поток выполняет чтение или запись в то же место, программа имеет гонку данных, и поведение программы не определено. Чтение между строк, компилятор будут Предположим, что никакой другой поток не записывает ваши данные. Ваша задача — предотвратить гонки данных. И нет, volatile
не влияет на это.
Если это не так, поможет ли ключевое слово volatile?
Он игнорируется компилятором (т.е. без оптимизации), а не потоком.
Каждый поток получает свои собственные копии параметров, представляющих вызов, который произошел в этом потоке. Значение ‘p’ будет использоваться только в том случае, если на самом деле все они указывают на одно и то же. Присвоение ‘p’ в другом потоке не повлияет на ‘p’ в этом потоке, поскольку они даже не являются одной и той же переменной.
На что указывает «р», это совершенно другая история. Это просто область памяти. Если другие потоки могут получить к нему доступ, они могут получить к нему доступ и могут писать в любое время. Единственный способ защитить что-то вроде этого — мьютекс.