Какая разница в использовании волатильности между C/С++ и С#/Java?

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

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

Ответ 1

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

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

Ответ 2

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

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

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

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 на _-й итерации, тогда действие a обязательно должно предшествовать всем последующим летучим функциям, применяемым к b.

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

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

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

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

В 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/С++ не будет вести себя так же, как это делает Java. Независимо от того, зависит ли это от (1), будет ли компилятор выполнять любое переупорядочение кода, которое может быть в удивительном порядке, но законным порядком, и (2) следует ли, если базовая машинная архитектура поддерживает тот же строгий порядок памяти, при условии, что компилятор не выполняет какого-либо удивительного переупорядочения кода.

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

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

Ответ 3

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