Re[3]: volatile у переменной класса
От: emusic Франция https://software.muzychenko.net/ru
Дата: 10.01.05 19:23
Оценка: 29 (3) +1
Здравствуйте, c-smile, Вы писали:

CS>EnterCriticalSection/LeaveCriticalSection это два раза полновесный вызов Scheduler что не способствует быстродействию никак.


Надо отдать должное реализации этих функций: если секция не захвачена другим потоком — объекты синхронизации не задействуются, все выливается только в вызовы InterlockedXXX.
... << RSDN@Home 1.1.4 beta 3 rev. 185>>
Re[4]: volatile у переменной класса
От: c-smile Канада http://terrainformatica.com
Дата: 10.01.05 19:28
Оценка:
Здравствуйте, MaximE, Вы писали:

ME>Я говорил про volatile.


ME>Никто не отрицает, что дешевле вызвать InterlockedExchange, чем pthread_mutex_acquire/EnterCriticalSection/etc...


"Но если один из потоков изменяет переменную, синхронизация при помощи мютексов обязательна." (С) MaximE
Re[4]: volatile у переменной класса
От: c-smile Канада http://terrainformatica.com
Дата: 10.01.05 19:29
Оценка:
Здравствуйте, emusic, Вы писали:

E>Здравствуйте, c-smile, Вы писали:


CS>>EnterCriticalSection/LeaveCriticalSection это два раза полновесный вызов Scheduler что не способствует быстродействию никак.


E>Надо отдать должное реализации этих функций: если секция не захвачена другим потоком — объекты синхронизации не задействуются, все выливается только в вызовы InterlockedXXX.


Спасибо, буду знать. В такие глубины я не залазил.
Re[2]: читаем про volatile
От: c-smile Канада http://terrainformatica.com
Дата: 10.01.05 19:51
Оценка: :)
Здравствуйте, MaximE, Вы писали:

Ну если ты не веришь хлопцам от MS, то вот тебе от GCC

Atomicity

.....Worse still, "smart" compilers like GCC will often perform optimizations that could eliminate the memory operations needed to ensure that other processors can see what this processor has done. Fortunately, both these problems can be remedied... leaving only the relationship between access efficiency and cache line size for us to worry about.

Volatility

To prevent GCC's optimizer from buffering values of shared memory objects in registers, all objects in shared memory should be declared as having types with the volatile attribute. If this is done, all shared object reads and writes that require just one word access will occur atomically.


И дальше по теме "Linux Parallel Processing HOWTO"
http://howtos.linux.com/howtos/Parallel-Processing-HOWTO-2.shtml

(свой зуб шли заказным письмом)
Re[3]: читаем про volatile
От: MaximE Великобритания  
Дата: 10.01.05 20:03
Оценка:
c-smile wrote:

> Здравствуйте, MaximE, Вы писали:

>
> Ну если ты не веришь хлопцам от MS, то вот тебе от GCC
>
>

>
> Atomicity
>
> .....Worse still, "smart" compilers like GCC will often perform optimizations that could eliminate the memory operations needed to ensure that other processors can see what this processor has done. Fortunately, both these problems can be remedied... leaving only the relationship between access efficiency and cache line size for us to worry about.
>
> Volatility
>
> To prevent GCC's optimizer from buffering values of shared memory objects in registers, all objects in shared memory should be declared as having types with the volatile attribute. If this is done, all shared object reads and writes that require just one word access will occur atomically.


Во первых, я нигде не отрицал того, что здесь буквально написано. Во-вторых, здесь ни слова ни про multithreading ни про visibility.

> (свой зуб шли заказным письмом)


Вышлю, когда ты мне напишешь, что volatile гарантирует что все процессоры будут видеть изменения над volatile переменными без барьеров памяти.

--
Maxim Yegorushkin
Posted via RSDN NNTP Server 1.9
Re[4]: читаем про volatile
От: c-smile Канада http://terrainformatica.com
Дата: 10.01.05 20:43
Оценка: 9 (1)
Здравствуйте, MaximE, Вы писали:

>> (свой зуб шли заказным письмом)


ME>Вышлю, когда ты мне напишешь, что volatile гарантирует что все процессоры будут видеть изменения над volatile переменными без барьеров памяти.


Трам-та-ра-рам, Макс, ну причем здесь volatile и процессор?
volatile это хинт компилятору-оптимизатору не больше и не меньше. GCC и VC его могут интерпретировать по разному. Как и все остальные.

InterlockedExchange например это intrinsic функция в VC. VC в принципе знает про архитекуру ОС и threads. Поэтому там volatile активно используется для программирования межпоточного взаимодействия. Сответсвенно все функции Interlocked* (10шт) имеют volatile аргументы.

(Зуб лучше слать заказным письмом DHL — у меня день рождения скоро)
Re[7]: volatile у переменной класса
От: Murr Россия  
Дата: 10.01.05 22:31
Оценка:
Здравствуйте, MaximE, Вы писали:

>> Наличие барьеров без volatile не гарантирует правильной работы. Наличие volatile без барьеров — тоже не гарантирует. volatile обеспечивает поддержку со стороны языка, барьер — со стороны аппаратуры.


ME>Это ерунда. На POSIX все барьеры работают без volatile. POSIX работает практически на любой архитектуре. Почему это вдруг в vindoze на той же архитектуре понадобились volatile? Ответ один — от недопонимания.


На самом деле мир сложнее.
Библиотеки POSIX — примерно как жены из сказки — умные, хорошие, красивые, но бывают только в книжках, а в жизни совсем не такие. Кроме того, область их применения довольно узка, чтобы рекомендовать их как панацею.
Все уже давно научились обходиться без них и решают свои проблемы самостоятельно.

Вроде ж мы уже договорились, что в тех же Windows и Linux через дельта-т (время до первого прерывания) вторая нить обязательно увидит обновления, сделанные первой нитью. Может подход не слишком академичный, но ведь с volatile сие в любом случае работает. Разумеется, при использовании более сложной схемы обработки нужно использовать либо барьеры либо даже ядреные примитивы синхронизации. Если нужно все сразу, то тут уж ничего не попишешь и нужно делать сброс памяти (те же InterlockedExchange или set_mb), но сие, IMHO, не совсем правильный подход(разве что в исключительных случаях).


>> Зачем, по-твоему, вообще существует volatile? Именно для урезания вольностей оптимизатора в отношении состояния объекта.


ME>volatile был введен в C и на сегодняшний день нужен только для асинхронных обработчиков сигналов. Точка.


Ну не совсем так.
Но, что правда, compiler barrier а-ля линуксового barrier() действительно зачастую использовать и удобнее и производительнее.
Re[5]: читаем про volatile
От: emusic Франция https://software.muzychenko.net/ru
Дата: 11.01.05 05:25
Оценка:
Здравствуйте, c-smile, Вы писали:

CS>Сответсвенно все функции Interlocked* (10шт) имеют volatile аргументы.


Справедливости ради надо сказать, что в volatile их аргументы переделали не так давно — еще в заголовках от VC++ 6.0 и в DDK выпусков до 2002 года их нет, отчего мне постоянно приходилось переопределять
... << RSDN@Home 1.1.4 beta 3 rev. 185>>
Re[6]: читаем про volatile
От: c-smile Канада http://terrainformatica.com
Дата: 11.01.05 05:40
Оценка: :))
Здравствуйте, emusic, Вы писали:

CS>>Сответсвенно все функции Interlocked* (10шт) имеют volatile аргументы.


E>Справедливости ради надо сказать, что в volatile их аргументы переделали не так давно — еще в заголовках от VC++ 6.0 и в DDK выпусков до 2002 года их нет, отчего мне постоянно приходилось переопределять


Было такое дело.

ПыСы: Можешь помочь с благородным делом вынимания зуба из Максима Егорушкина и пересылки его (зуба, хотя можно и самого Макса)?
Re[7]: volatile у переменной класса
От: emusic Франция https://software.muzychenko.net/ru
Дата: 11.01.05 06:51
Оценка: 11 (3) -1
Здравствуйте, MaximE, Вы писали:

ME>Атомарность и memory visibility ортогональны. См. мой предыдущий ответ.


Ты упорно пытаешься все свести к многопроцессорному параллелизму. Однако существует еще и однопроцессорный, и будет существовать еще довольно долго. Если заведомо известно, что код работает только на одном процессоре (программа для микроконтроллера, ядро однопроцессорной ОС и т.п.) — что ты ей посоветуешь, кроме volatile?

>>>> Функции используются только для изменения volatile-переменных. Чтение их значений может происходить в параллельных потоках без каких-либо функций.

>>
>> ME>Это так только по случайному стечению обстоятельств на IA32.
>>
>> Почему по случайному? Еще не так давно подавляющее большинство платформ работало именно так.

ME>Мы же работаем сегодня, а не вчера, верно?


И сегодня так работает великое множество платформ. Не следует под словом "платформа" понимать непременно "большой многогигагерцовый компьютер". Количество платформ в сфере тех же мобильных устройств можешь себе представить? Параллелизма там — выше крыши. Но вот аппаратного переупорядочивания команд чаще всего нет.

>> ME> Именно по этой причине на всех современных RISC процессорах, а также на IA64, тебе придется использовать барьеры памяти чтобы прочитать актуальное значение.

>>
>> Именно этим может и заниматься компилятор, обрабатывая volatile.

ME>Ошибаешься. volatile не вставляет никаких барьеров. Барьеры обеспечиваются ф-циями


А что ему мешает их вставлять, интересно? Не вставляет — такова реализация. Но барьеры без volatile особого смысла не имеют. Если программа с глубокой оптимизацией и параллелизмом правильно работает без volatile — это либо недостатки компилятора, либо счастливое стечение обстоятельств.

>> ME>С тем, что состояние программы после sequence point is indeterminate.

>>
>> Из чего это следует?

ME>Из стандарта С/С++.


Покажи, пожалуйста, пальцем на подобное утверждение в стандарте. Лично я там вижу прямо противоположное:

An expression can result in a value and can cause side effects.


То есть, значение выражения является его основным результатом, а отнюдь не побочным эффектом. И ничто не запрещает это значение использовать в дальнейшейм без повторного вычисления выражения, если есть уверенность, что оно не изменилось.

>> Модификация объекта, согласно стандарту, есть sequence point.


ME>Вставь вызов ф-ции.


Почему именно вызов функции? Ты упирал на sequence points, но выяснилось, что из всех sequence points твою точку зрения подтверждает только вызов функции. А знаешь почему? Потому, что — сюрприз — есть такая штука, как aliasing. Компилятор до последнего справедливо предполагает, что в неизвестных ему функциях этот aliasing может присутствовать. Однако, если ты определишь какую-нибудь простую функцию (для VC 6.0 — inline, для 7.0 можно и обычную), то очень удивишься — ее вызов между проверкой переменной на нуль и повторным использованием значения отнюдь не заставляет компилятор перечитывать переменную заново. Если она, конечно, не volatile.

А вот тебе пример с твоей любимой InterlockedXXX:

LONG f (LONG &a, LONG &b, LONG &c) {
  if (!a) {
    InterlockedIncrement (&c);
    b = a;
  }
  return b;
}


И VC 6.0, и 7.0 с /Oa дадут именно то, что и ожидалось — запись в b константного нуля. И возврат его же.

>> Где в C++ барьеры?


ME>В С++ их нет, в с++ нет multithreadind.


Правильно. Поэтому корректная работа должна обеспечиваться с двух сторон — со стороны компилятора (volatile), и со стороны аппаратуры (когеретность/барьеры). В одностороннем порядке — не получится.

>> Наличие барьеров без volatile не гарантирует правильной работы. Наличие volatile без барьеров — тоже не гарантирует.


ME>Это ерунда.


У тебя — ерунда, на деле — истина

ME> На POSIX все барьеры работают без volatile.


Что значит "на POSIX"? С каких пор POSIX стал как-то влиять на особенности оптимизации сишного кода? Это, как ты выразился в отношении i86 — стечение обстоятельств.

ME> POSIX работает практически на любой архитектуре. Почему это вдруг в vindoze на той же архитектуре понадобились volatile? Ответ один — от недопонимания.


Ну да, конечно Все вокруг уже черт знает сколько лет недопонимают, один ты владеешь истиной
... << RSDN@Home 1.1.4 beta 3 rev. 185>>
Re[5]: читаем про volatile
От: MaximE Великобритания  
Дата: 11.01.05 07:27
Оценка: 6 (1)
c-smile wrote:

> Здравствуйте, MaximE, Вы писали:

>
>>> (свой зуб шли заказным письмом)
>
> ME>Вышлю, когда ты мне напишешь, что volatile гарантирует что все процессоры будут видеть изменения над volatile переменными без барьеров памяти.
>
> Трам-та-ра-рам, Макс, ну причем здесь volatile и процессор?
> volatile это хинт компилятору-оптимизатору не больше и не меньше.

С этим я абсолютно согласен.

> GCC и VC его могут интерпретировать по разному. Как и все остальные.


Насколько я знаю, volatile не заставляет генериться кода больше, чем нужно для зачитывания переменной из памяти (а не из регистра).

> InterlockedExchange например это intrinsic функция в VC. VC в принципе знает про архитекуру ОС и threads. Поэтому там volatile активно используется для программирования межпоточного взаимодействия. Сответсвенно все функции Interlocked* (10шт) имеют volatile аргументы.


Мои вопросы:

  1. Как конкретно помогает volatile написанию thread safe кода?
  2. Хотелось бы увидеть кусок кода, который испрользует Interlocked* ф-ции для изменения глобальной переменной, разделяемой между потоками, и который не работал бы если переменная не volatile. Для чистоты эксперимента, объявить ф-ции Interlocked* или скопировать их реализацию без volatile.

--
Maxim Yegorushkin
Posted via RSDN NNTP Server 1.9
Re[5]: volatile у переменной класса
От: MaximE Великобритания  
Дата: 11.01.05 07:31
Оценка: -1
c-smile wrote:

> Здравствуйте, MaximE, Вы писали:

>
> ME>Я говорил про volatile.
>
> ME>Никто не отрицает, что дешевле вызвать InterlockedExchange, чем pthread_mutex_acquire/EnterCriticalSection/etc...
>
> "Но если один из потоков изменяет переменную, синхронизация при помощи мютексов обязательна." (С) MaximE

Добавить сюда Interlocked* и __exchange_and_add/etc..

--
Maxim Yegorushkin
Posted via RSDN NNTP Server 1.9
Re[8]: volatile у переменной класса
От: MaximE Великобритания  
Дата: 11.01.05 07:45
Оценка: 3 (1)
emusic wrote:

> Здравствуйте, MaximE, Вы писали:

>
> ME>Атомарность и memory visibility ортогональны. См. мой предыдущий ответ.
>
> Ты упорно пытаешься все свести к многопроцессорному параллелизму.

Да, а не к симуляции.

> Однако существует еще и однопроцессорный, и будет существовать еще довольно долго. Если заведомо известно, что код работает только на одном процессоре (программа для микроконтроллера, ядро однопроцессорной ОС и т.п.) — что ты ей посоветуешь, кроме volatile?


volatile реально может здесь помочь, запретив компилятору кэшировать значение переменной в регистре. Затем портировав прогу на другую платформу можно долго отлаживаться, затем, наматерившись вдоволь, выкинуть код и переписать его заново.

[]

>>> ME> Именно по этой причине на всех современных RISC процессорах, а также на IA64, тебе придется использовать барьеры памяти чтобы прочитать актуальное значение.

>>>
>>> Именно этим может и заниматься компилятор, обрабатывая volatile.
>
> ME>Ошибаешься. volatile не вставляет никаких барьеров. Барьеры обеспечиваются ф-циями
>
> А что ему мешает их вставлять, интересно? Не вставляет — такова реализация. Но барьеры без volatile особого смысла не имеют. Если программа с глубокой оптимизацией и параллелизмом правильно работает без volatile — это либо недостатки компилятора, либо счастливое стечение обстоятельств.

Возможно в будущем, когда будет разработана C++ memory model for multithreading, он и будет их вставлять.

[]

> Ну да, конечно Все вокруг уже черт знает сколько лет недопонимают, один ты владеешь истиной


Я тоже не владею.

Просто UNIX community имеет более долгую историю, чем windows community, поэтому я склонен больше доверять первым.

--
Maxim Yegorushkin
Posted via RSDN NNTP Server 1.9
Re[9]: volatile у переменной класса
От: emusic Франция https://software.muzychenko.net/ru
Дата: 11.01.05 07:55
Оценка: +1 -1
Здравствуйте, MaximE, Вы писали:

ME>volatile реально может здесь помочь, запретив компилятору кэшировать значение переменной в регистре. Затем портировав прогу на другую платформу можно долго отлаживаться, затем, наматерившись вдоволь, выкинуть код и переписать его заново.


Нет. Из этого следует совершенно элементарный вывод: для обеспечения правильной работы кода на конкретной платформе нужны две вещи: volatile, который сообщит компилятору, что объект может модифицироваться извне, и средства синхронизации платформы, которые обеспечат правильное прохождение изменений из потока в поток.

Если тебе удается успешно обходиться без volatile, одними примитивами — это не более, чем случайность. Весьма, впрочем, распространенная ввиду того, что нынешние оптимизаторы в большинстве случаев справедливо опасаются использовать кэшированные ранее значения после вызова неизвестной функции (тот самый aliasing, разговор о котором ты предпочел не развивать). Но, попадись такой код мощному оптимизатору, который не поленится проанализировать вызываемую функцию, или окажись примитивы синхронизации реализованными в более явном виде, этот код нормально работать перестанет. И неожиданным это будет лишь для тебя
... << RSDN@Home 1.1.4 beta 3 rev. 185>>
Re[6]: читаем про volatile
От: emusic Франция https://software.muzychenko.net/ru
Дата: 11.01.05 15:15
Оценка:
Здравствуйте, MaximE, Вы писали:

ME>
  • Хотелось бы увидеть кусок кода, который испрользует Interlocked* ф-ции для изменения глобальной переменной, разделяемой между потоками, и который не работал бы если переменная не volatile.
    ME>[/list]

    Отчего ты так уперся в Interlocked*? Из чего следует, что оба параллельных потока непременно будут изменять переменную? Один поток может изменять, а другой — только опрашивать. Можно, конечно, извратиться посредством InterlockedExchangeAdd с нулем, но это будет именно ненужное извращение.

    Когда оба потока используют Interlocked* в отношении одной переменной — разумеется, компилятор не знает, что функция будет делать с переданной переменной, и всяко сгенерит повторное чтение. Если для организации барьера используется целевой примитив, которому передается ссылка на объект — будет то же самое.

    А вот в ядре виндов барьер делает функция KeMemoryBarrier без параметров — откуда компилятор после ее вызова узнает, что значение не-volatile переменной могло измениться? Потом, если производится обширная работа с множеством объектов внутри критической секции — откуда компилятору узнать, что внутри секции нужно заново перечитывать данные из памяти? Это ему сообщит либо volatile, либо запрет глубокой оптимизации.
    ... << RSDN@Home 1.1.4 beta 3 rev. 185>>
  • Re[6]: читаем про volatile
    От: Seriously Serious  
    Дата: 11.01.05 18:01
    Оценка:
    Здравствуйте, MaximE, Вы писали:

    ME>

      ME>
    1. Как конкретно помогает volatile написанию thread safe кода?
      ME>

    тут можно посмотреть, хотя я с этим не совсем согласен.
    Re[7]: читаем про volatile
    От: MaximE Великобритания  
    Дата: 11.01.05 19:32
    Оценка: :)
    Здравствуйте, Seriously Serious, Вы писали:

    SS>тут можно посмотреть, хотя я с этим не совсем согласен.


    За эту статью Александреску был публично выпорон
    Re[3]: volatile у переменной класса
    От: Шахтер Интернет  
    Дата: 12.01.05 01:04
    Оценка: +1 :)
    Здравствуйте, MaximE, Вы писали:

    >> Желательно еще установку этой переменной выполнять с помощью InterlockedExchange.

    >> Собственно так как эта функция объявлена как
    >>
    >>
    >> LONG InterlockedExchange(
    >>   LPLONG volatile Target, // value to exchange
    >>   LONG Value              // new value
    >> );
    >>

    >>
    >> без объявления volatile у тебя ничего и не получится.

    ME>Наверное, LPLONG volatile* (star) Target? Почему же без volatile не получиться? Как и в функцию, которая принимает указатель на константный объект мы можем передать указатель на неконстнантный объект, но но не наооборот, так и в функциию принимающую указатель на волатильный, мы можем передать указатель на неволатильный объект.


    ME>Вообще, квалификатор volatile у всех Interlocked* функций абсолютно бесполезен, и даже вреден, так как сбивает людей с толку. Так как это ф-ции, то они представляют для компилятора sequence points. После sequence points, компилятор обязан перечитывать значения переменных из памяти, неважно, volatile ли, const ли, или это переменная без cv-квалификатора, и оптимизатор здесь не может ничего сделать.


    ME>--

    ME>Maxim Yegorushkin

    Он не бесполезен, а необходим. Иначе ты не сможешь написать

    volatile LONG var;
    
    InterlockedExchnage(&var,1);
    ... << RSDN@Home 1.1.0 stable >>
    В XXI век с CCore.
    Копай Нео, копай -- летать научишься. © Matrix. Парадоксы
    Re[4]: volatile у переменной класса
    От: MaximE Великобритания  
    Дата: 12.01.05 05:25
    Оценка: 3 (1) :))
    Здравствуйте, Шахтер, Вы писали:

    []

    ME>>Вообще, квалификатор volatile у всех Interlocked* функций абсолютно бесполезен, и даже вреден, так как сбивает людей с толку. Так как это ф-ции, то они представляют для компилятора sequence points. После sequence points, компилятор обязан перечитывать значения переменных из памяти, неважно, volatile ли, const ли, или это переменная без cv-квалификатора, и оптимизатор здесь не может ничего сделать.


    Ш>Он не бесполезен, а необходим. Иначе ты не сможешь написать


    Ш>volatile LONG var;
    
    Ш>InterlockedExchnage(&var,1);
    Ш>


    Да, это единственная причина, зачем эти функции принимают volatile аргумент.
    Re: volatile у переменной класса
    От: yurafitt  
    Дата: 12.01.05 10:36
    Оценка: +1
    Здравствуйте, Vet, Вы писали:

    Vet>В объекте класса есть переменная, которая используется двумя потоками.

    Vet>Один из потоков иногда меняет ее значение.
    Vet>Есть ли необходимость в этом случае делать переменную как volatile.
    Vet>И зависит ли ответ от того, сздан ли объект класса на стеке или в динамической памяти.

    Vet>Вопрос вызван тем, что у Рихтера прочитал, что если глобальная переменная используется

    Vet>разными потоками, то она обязана быть volatile. Вот меня и рабирают сомнения нужно ли
    Vet>тоже самое делать для переменных(членов) класса.

    volatile нужно для того чтобы компилятор не кешировал значение переменной. Т.Е. Обычно компилятор оптимизирует использование переменных путем помещения их значения в регистры процессора. Если установить у переменной идентификатор volatile, то компилятор создаст такой код при котором при доступе к переменной её значение всегда будет читаться из памяти, и это значение не будет помещятся в регистры процесора.
    Данная техника полезна в многопоточных приложениях, в том случае когда один поток записывает значение в переменную, а другой читает. Если в этом случае у переменной не будет модификатора volatile то может получится так, что компилятор поместит значения переменной в двух потоках в регистры процессора, и тогда изменение значение переменной в одном потоке, не повлияет на изменение переменной в другом потоке.
    Подождите ...
    Wait...
    Пока на собственное сообщение не было ответов, его можно удалить.