Здравствуйте, Gregory, Вы писали:
G>как понимать const volatile и зачем оно такое нужно?
volatile означает, что объект может изменяться как-то помимо действий программы, const — объект действиями программы через данный идентификатор не изменяется. const volatile — объект изменяется только "внешними" по отношению к программе способами. Например, данные какого-то внешнего устройства, отображенные на оперативную память.
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
G>>как понимать const volatile и зачем оно такое нужно?
ПК>volatile означает, что объект может изменяться как-то помимо действий программы, const — объект действиями программы через данный идентификатор не изменяется. const volatile — объект изменяется только "внешними" по отношению к программе способами. Например, данные какого-то внешнего устройства, отображенные на оперативную память.
А также, и это наиболее важное применение: что объект может поменяться за пределами "прямой видимости":
— в другом потоке
— в какой-либо функции
Особенно это существенно для указателей и ссылок: могут одновременно существовать несколько разных способов доступиться до одного и того же предмета.
const — накладывает ограничение на модификацию "предмета" через данный идентификатор/ссылку/указатель,
volatile — сообщает компилятору, что нельзя кэшировать значение "предмета", т.к. он может неявно измениться в любой момент.
Здравствуйте, Кодт, Вы писали:
К>const — накладывает ограничение на модификацию "предмета" через данный идентификатор/ссылку/указатель, К>volatile — сообщает компилятору, что нельзя кэшировать значение "предмета", т.к. он может неявно измениться в любой момент.
Кэшировать в данном случае — размещать в регистрах и всяких других местах, которые могут быть недоступны из других процессов, функций, и т.п.
- Вы знаете — жаль, просто по-человечески жаль Памелу Андерсон, которая никогда не сможет сыграть на баяне...
Re[3]: const volatile
От:
Аноним
Дата:
28.03.03 14:59
Оценка:
Здравствуйте, Кодт, Вы писали:
К>А также, и это наиболее важное применение: что объект может поменяться за пределами "прямой видимости": К>- в другом потоке К>- в какой-либо функции
К>Особенно это существенно для указателей и ссылок: могут одновременно существовать несколько разных способов доступиться до одного и того же предмета.
Неправда ваша. Квалификация невозможности доступа по разным путям существует в Си и называется он restrict. В Си++ такой квалификации нет. А volatile к этому отношения не имеет.
Здравствуйте, Аноним, Вы писали:
К>>Особенно это существенно для указателей и ссылок: могут одновременно существовать несколько разных способов доступиться до одного и того же предмета.
А>Неправда ваша. Квалификация невозможности доступа по разным путям существует в Си и называется он restrict. В Си++ такой квалификации нет. А volatile к этому отношения не имеет.
Видимо, мы друг друга недопоняли.
Несколько указателей на один и тот же предмет.
Один из них — указатель на константу.
Через другой — объект модифицируется.
Без volatile компилятор имеет право оптимизировать проверки *1*, *2*, например, запомнив результат в регистре, временной переменной, флаге состояния процессора... Что, естественно, приведет к некорректной работе.
Этот пример, конечно же, притянут за уши. Но в многопоточных приложениях — такое возможно с легкостью необычайной.
Здравствуйте, Кодт, Вы писали:
А>>Неправда ваша. Квалификация невозможности доступа по разным путям существует в Си и называется он restrict. В Си++ такой квалификации нет. А volatile к этому отношения не имеет.
К>Видимо, мы друг друга недопоняли.
К>Несколько указателей на один и тот же предмет. К>Один из них — указатель на константу. К>Через другой — объект модифицируется.
К>Пример: К>
К>Без volatile компилятор имеет право оптимизировать проверки *1*, *2*, например, запомнив результат в регистре, временной переменной, флаге состояния процессора... Что, естественно, приведет к некорректной работе.
Если он благородный (т. е. соответствующий стандарту) компилятор, он такого трюка не сделает. Компилятор не имеет возможности делать предположения об отсутствии иных ссылок, посредством коих значение text[0] может быть изменено по ходу исполнения программы.
В Си есть возможность квалификации restrict:
void view(const restrict char* text);
Вот в таком случае компилятор имеет законное право выполнять такую оптимизацию.
К>Этот пример, конечно же, притянут за уши.
Даже очень.
К>Но в многопоточных приложениях — такое возможно с легкостью необычайной.
Это иная история, приведенный вами пример к ней отношения не имеет; вот там — действительно царство volatile.
Здравствуйте, <Аноним>, Вы писали:
А>Если он благородный (т. е. соответствующий стандарту) компилятор, он такого трюка не сделает. Компилятор не имеет возможности делать предположения об отсутствии иных ссылок, посредством коих значение text[0] может быть изменено по ходу исполнения программы.
Если мы говорим об одном потоке, то изменение данных через другую ссылку компилятор прелестно отследит и предварительно сбросит их из кеша. Поэтому кешировать данные ничто не мешает.
А если о нескольких -- тогда действительно volatile.
RSDN@Home
Кто здесь?!
Re[7]: const volatile
От:
Аноним
Дата:
29.03.03 15:03
Оценка:
Здравствуйте, _wqwa, Вы писали:
А>>Если он благородный (т. е. соответствующий стандарту) компилятор, он такого трюка не сделает. Компилятор не имеет возможности делать предположения об отсутствии иных ссылок, посредством коих значение text[0] может быть изменено по ходу исполнения программы. W>Если мы говорим об одном потоке, то изменение данных через другую ссылку компилятор прелестно отследит и предварительно сбросит их из кеша. Поэтому кешировать данные ничто не мешает.
Кэшировать, кэш, сбросить из кэша — это вы о чем вообще? О каком еще таком кэше? Который к тому же и компилятор сбрасывает?
Здравствуйте, Аноним, Вы писали:
К>>Без volatile компилятор имеет право оптимизировать проверки *1*, *2*, например, запомнив результат в регистре, временной переменной, флаге состояния процессора... Что, естественно, приведет к некорректной работе.
А>Если он благородный (т. е. соответствующий стандарту) компилятор, он такого трюка не сделает. Компилятор не имеет возможности делать предположения об отсутствии иных ссылок, посредством коих значение text[0] может быть изменено по ходу исполнения программы.
По-Вашему получается совершенно жуткая картина — запрещена практически любая оптимизация доступа к памяти вне стека.
И при оптимизации примера
if (*a == 0) *a += 2;
возможны два варианта:
1. если позволяет железо делаем все за один такт
2. в противном случае читаем по адресу a дважды — это же маразм, на фига нужна такая оптимизация?!
А если допустить такое извращение — поток №2 получил указатель на стек потока №1 (ну технически-то возможно ), то нужно запретить кэширование в регистрах даже стековых значений!!!
В чем же разница между volatile и не volatile в Вашей интерпретации?
Нигде ни читал подобного явным текстом, но всегда полагал существование у компилятора некой презумпции однопоточности — предполагается что значение может быть изменено только из текущего потока, если не указано обратное — volatile. Разве это не так?
Здравствуйте, Диагностик, Вы писали:
Д> всегда полагал существование у компилятора некой презумпции однопоточности - Д> предполагается что значение может быть изменено только из текущего Д> потока, если не указано обратное — volatile. Разве это не так?
Зависит от конкретной реализации, но в общем именно так и есть.
Posted via RSDN NNTP Server 1.4.6 beta
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Здравствуйте, Аноним, Вы писали:
А>Кэшировать, кэш, сбросить из кэша — это вы о чем вообще? О каком еще таком кэше? Который к тому же и компилятор сбрасывает?
Значения переменных, результаты вычисления выражений — записываются в различные временные переменные (физически расположенные как в регистрах процессора, так и в памяти).
Отчасти это обусловлено архитектурой процессоров, отчасти — соображениями оптимизации.
Эти временные переменные и зовут в данном случае кэшем.
Так вот, у временных переменных есть "срок годности", т.е. текущее значение совпадает с правильным некоторое время.
Например, содержимое регистра EAX не меняется до перезаписи и до вызова функции (точнее, там его значение не гарантируется).
Поэтому
int *x, y, z;
...
y = x[0] * 2;
z = x[0] * 3;
printf("hello");
t = x[0] * 4;
можно оптимизировать, считав значение x[0] в EAX и затем использовать его в вычислении y, z. После выполнения printf значение EAX станет другим, поэтому t потребует новой загрузки x[0].
Но компилятор может объехать эту проблему, загрузив x[0] во временную переменную x0, размещенную на стеке.
Кэш "портится" не только сам по себе, но и потому, что исходные данные изменились.
Если компилятор может это отследить, например,
y = x[0] * 2;
x[0]++; // изменилось значение по тому же адресу
z = x[0] * 3;
x++; // изменился сам адрес
t = x[0] * 4;
то кэш будет "сброшен".
Но, как уже говорилось выше, значение могут поменять "со стороны". В таком случае переменную объявляют volatile.
Я просто-таки удивлен этаким вашим "разъяснением". Все, надеюсь, и так отлично знают, как устроен процессор. Все в курсе, что у процессора есть регистры. Однако регистры — это не кэш! У данных в регистрах нет "срока годности". Компилятор "сбрасыванием" кэша не занимается.
Компилятор может генерировать код, который выполняет действия над повторно употребляемыми объектами в регистрах. Но это не кэширование по своей сути.
Здравствуйте, <Аноним>, Вы писали:
А>Я просто-таки удивлен этаким вашим "разъяснением". Все, надеюсь, и так отлично знают, как устроен процессор. Все в курсе, что у процессора есть регистры. Однако регистры — это не кэш! У данных в регистрах нет "срока годности". Компилятор "сбрасыванием" кэша не занимается.
Речь идет о том, что перед каждой операцией над volatile переменной, значение этой переменной необходимо считать из памяти заново, даже если это значение осталось в одном из регистров. Компилятор генерирует код, "сбрасывающий кэш" (т.е. перечитывающий значение переменной в регистр заново).
А>Компилятор может генерировать код, который выполняет действия над повторно употребляемыми объектами в регистрах. Но это не кэширование по своей сути.
Назови это, как считаешь правильным. И напиши здесь свое объяснение на тему volatile. Это будет интереснее, чем читать бесконструктивные придирки.
Здравствуйте, Аноним, Вы писали:
А>Я просто-таки удивлен этаким вашим "разъяснением". Все, надеюсь, и так отлично знают, как устроен процессор. Все в курсе, что у процессора есть регистры. Однако регистры — это не кэш! У данных в регистрах нет "срока годности". Компилятор "сбрасыванием" кэша не занимается.
Не путайте аппаратный кэш процессора и временные переменные, используемые программой (порожденной компилятором).
Например, регистр AX|EAX, интенсивно используемый в процессорах x86 — это именно кэш, поскольку в оригинальной программе на Си о нем не упоминается.
А>Компилятор может генерировать код, который выполняет действия над повторно употребляемыми объектами в регистрах. Но это не кэширование по своей сути.
Именно кэширование по своей сути (хранение значений в памяти с быстрым доступом).
И необязательно в регистры процессора, но также в память на стеке и TLS.
Перекуём баги на фичи!
Re[11]: const volatile
От:
Аноним
Дата:
31.03.03 09:04
Оценка:
Здравствуйте, Михаил Можаев, Вы писали:
ММ>Назови это, как считаешь правильным. И напиши здесь свое объяснение на тему volatile. Это будет интереснее, чем читать бесконструктивные придирки.
volatile мы уже проехали, вопрос в том, что употребление слова "кэш" здесь неверно и может вводить в заблуждение относительно того, как это все работает.
Re[11]: const volatile
От:
Аноним
Дата:
31.03.03 09:12
Оценка:
Здравствуйте, Кодт, Вы писали:
К>Именно кэширование по своей сути (хранение значений в памяти с быстрым доступом). К>И необязательно в регистры процессора, но также в память на стеке и TLS.
Неверно, регистры, по своей сути — это не кэш, а опративное хранилище.
Кэш — это более быстродействующая область памяти, функционально эквивалентная основной. Регистры функционально не эквивалентны, т. к. допускают обработку данных, невозможную для основной памяти.
В кэш данные помещаются в соответствии со стратегией кэширования, в предположении о возможности их использования в дальнейшем.
В регистры — в соответствии с алгоритмом, зная о возможности их использования в дальнейшем.
Пассаж про данные на стеке и в TLS вообще не ясен (особенно учитывая скорость доступа в TLS).
Re[7]: const volatile
От:
Аноним
Дата:
31.03.03 09:17
Оценка:
Здравствуйте, Диагностик, Вы писали:
Д>По-Вашему получается совершенно жуткая картина — запрещена практически любая оптимизация доступа к памяти вне стека.
Нет, отчего же.
Д>И при оптимизации примера Д>
Д>if (*a == 0) *a += 2;
Д>
Д>возможны два варианта: Д>1. если позволяет железо делаем все за один такт Д>2. в противном случае читаем по адресу a дважды — это же маразм, на фига нужна такая оптимизация?!
Этот пример отличается от предыдущего, по ходу выполнения в нем нет между двумя ссылками на *a других ссылок, потенциально могущих вести к тому же объекту, что и *a. Здесь оптимизация возможна.
Д>Нигде ни читал подобного явным текстом, но всегда полагал существование у компилятора некой презумпции однопоточности — предполагается что значение может быть изменено только из текущего потока, если не указано обратное — volatile. Разве это не так?
В общем, так; разъяснение выше дано именно исходя из этого.