В чем разница использования volatile между C / C ++ и C # / Java?

Я нашел это во многих ссылках, в которых упоминается, что volatile в C / C ++ является слабым и может вызывать проблемы в параллельной среде на нескольких процессорах, но его (volatile) можно использовать в качестве механизма связи между разностными ЦП в C # / Java. Кажется, что это ключевое слово более строгое в C # / Java, чем в C / C ++, но в чем разница / влияние между ними?

Вот ссылка на volatile на C / C ++. Почему volatile не считается полезным в многопоточном Программирование на C или C ++?


person Thomson    schedule 12.11.2013    source источник
comment
Если вы хотите узнать все подробности о Java, получите книгу Java Concurrency in Practice.   -  person Jesper    schedule 12.11.2013


Ответы (3)


Для C # / Java "volatile" сообщает компилятору, что значение переменной никогда не должно кэшироваться, поскольку его значение может измениться за пределами области действия самой программы. В этом случае компилятор избегает любых оптимизаций, которые могут привести к проблемам, если переменная изменяется «вне его контроля».

В C / C ++ "volatile" требуется при разработке встроенных систем или драйверов устройств, когда вам нужно читать или записывать аппаратное устройство с отображением в память. Содержимое конкретного регистра устройства может измениться в любое время, поэтому вам понадобится ключевое слово «volatile», чтобы гарантировать, что такой доступ не будет оптимизирован компилятором.

person Nadeem_MK    schedule 12.11.2013
comment
В C / C ++ предотвращение оптимизации доступа компилятором также означает указание компилятору не кэшировать. - person patchwork; 12.11.2013
comment
Java: это неполный эффект ключевого слова volatile. Доступ к переменной volatile также устанавливает связь происходит до между операциями в потоке. - person Alexey; 20.03.2018
comment
Похоже, что volatile в Java - это атомарная загрузка / сохранение с упорядочением приобретения-выпуска. - person Ibraheem Ahmed; 02.06.2021

Ключевое слово volatile очень субъективно для языка и платформы, на которой оно реализовано. В то время как Java обеспечивает согласованное поведение volatile для всех архитектур, это не относится к языкам, которые напрямую скомпилированы в платформу собственного компьютера, например, в случае C / C ++. Попробуем разобраться, почему это так.

Пусть a, b являются членами набора программных действий P, а v_ {n} (a) будет функцией, которая применяет требование изменчивости к действию, где нижний индекс _n обозначает _n-ю итерацию, в которой применяется изменчивое действие. , а \ rightarrow - оператор предшествования, который объяснялся ранее. Для всех действий программы действуют следующие правила:

v_n (а) \ rightarrow v_ {n + 1} (а)

a \ rightarrow v_n (b) \ Rightarrow a \ rightarrow v_ {n + i} (b) где i \ in \ mathbb {N}

Правило 1 говорит, что все изменчивые функции обеспечивают общий порядок, где функция v_ {n} (a) всегда предшествует v_ {n + 1} (a), где правило 2 говорит, что если действие a предшествует изменчивой функции для действия b на _n-й итерации, то действие a обязательно должно предшествовать всем последующим изменчивым функциям, применяемым к b.

Это очень сильное требование к памяти в Java, на самом деле оно намного сильнее, чем по сравнению с C / C ++. Спецификация языка C / C ++ не имеет такого ограничения на порядок памяти и оставляет на усмотрение реализации компилятора решение о том, как энергонезависимые действия упорядочиваются вокруг изменчивых действий.

Рассмотрим, как эти правила влияют на выполнение программы, на простом примере кода:

int a = 0;
int b = 0;
volatile int count = 0;

a  = 1;
count = 1;
b = 2;
count = 2;

В C / C ++ ключевое слово volatile гарантирует только то, что переменные count не могут быть переупорядочены относительно друг друга, т.е. если count == 2, то ему обязательно должно предшествовать count = 1. Однако нет ни гарантии, что a == 1, ни b == 2.

В Java, учитывая более строгую гарантию, определенную выше, тогда, если count == 1, тогда утверждение a == 1 должно быть истинным. Точно так же, если count == 2, тогда утверждение, что a == 1 && b == 2 должно быть истинным. Именно это означает строгая гарантия памяти, которую Java предлагает, а C / C ++ - нет.

Однако это не означает, что C / C ++ не будет вести себя так же, как Java. Будет ли это так, зависит от (1) того, выполняет ли компилятор какое-либо переупорядочение кода, которое может быть в неожиданном, но допустимом порядке, и (2) поддерживает ли архитектура базовой машины такой же строгий порядок памяти при условии, что компилятор не производит неожиданного переупорядочивания кода.

Например, компиляция кода на gcc с -O0, установленным на всех платформах x86, будет соответствовать модели памяти Java (и строже, чем), но другие архитектуры, такие как PowerPC, Alpha, Itanium, все поддерживают более слабую модель памяти, которая может показывать удивительную программу. поведение, которого программист может не ожидать. Будьте осторожны, лектор!

В любом случае, если вас интересуют дополнительные правила согласованности модели памяти, вы можете посмотреть объяснение Intel модели памяти x86, в котором подробно объясняются нюансы упорядочения памяти. Наслаждаться!

person sachin10    schedule 12.11.2013
comment
Означает ли это, что доступ к изменчивой переменной больше похож на барьер памяти в Java / C #? Есть ли официальные упоминания об этой семантике? - person Thomson; 12.11.2013
comment
@Thomson Проверьте это docs.oracle.com/javase/tutorial/essential/ параллелизм / - person sachin10; 12.11.2013

В C / C ++ volatile не имеет особой семантики, относящейся к многопоточности, поэтому его поведение в этом контексте зависит от платформы. C # и Java предоставляют особую семантику многопоточности для volatile. Итак, вы знаете, что получаете, и можете на это положиться.

person David Schwartz    schedule 12.11.2013
comment
Спасибо. Какую семантику многопоточности volatile обеспечивает в C # / Java? - person Thomson; 12.11.2013
comment
@Thomson Вы можете проверить документацию для отдельных языков, но основная идея состоит в том, что volatile обеспечивает как упорядочение, так и видимость между потоками на C # и Java. В C и C ++ ни то, ни другое не гарантируется. - person David Schwartz; 12.11.2013