Re[13]: [2]: : volatile: а можно примеры?
От: MaximE Великобритания  
Дата: 21.01.05 08:25
Оценка: 28 (5) +1 :)
c-smile wrote:

>

> ME>Во-первых, ты не привел кода, который мы просили привести: код, который использует ф-ции синхронизации для доступа к разделяемым переменным, но не работает когда эти разделяемые переменные не volatile.
>
> Просили привести реальный код где работают volatile. Я привел.

Вот что просили привести:

eao197 wrote:

> ... Поэтому еще раз проясню свою позицию: я хочу увидеть реальные примеры (из реальных, а не тестовых примеров), когда использовались примитивы синхронизации, но приложение все равно работало не правильно до тех пор, пока не было использовано volatile. При этом меня не интересуют ни обработчики аппаратных прерываний, ни работа с железом через отображаемые в память порты ввода/вывода.
>
> Прошу не приводить примеров, когда компилятору специальными ключами явно указывали, что ни одна функция не имеет побочных эффектов. Применение такого ключа в многопоточной программе, ИМХО, является проявлением излишнего оптимизма программиста. Кроме того, такой пример я уже видел. Может есть что-то еще?


Того что просили ты не привел.

>>> На моей задаче aliasing оптимизация дает 16% прирост производительности. Поэтому без этой оптимизации я даже и не компилирую.

>>> http://terrainformatica.com/htmlayout

Попытка использовать голые (не volatile) флаги вызывала очень странный behavior.
Вообще когда multithreading нечто начинает вести себя странно — ищи где ты забыл поставить volatile.


С этой опцией у тебя даже однопоточные программы будут глючить — поэтому тебе нужен volatile.

http://msdn.microsoft.com/library/en-us/vccore/html/_core_.2f.oa.2c_2f.ow.asp

Rules for Using /Oa and /Ow

  • If you use /Oa or /Ow, you must follow these rules. The following rules apply for any variable not declared as volatile:
  • No pointer can reference a variable that is used directly (a variable is referenced if it is on either side of an assignment or if a function uses it in an argument).
  • No variable can be used directly if a pointer to the variable is being used.
  • No variable can be used directly if its address is taken within a function.
  • No pointer can be used to access a memory location if another pointer modifies the same memory location.

    Failing to follow these rules can cause corrupted data. If variables seem to take on random values, compile the program with Disable (/Od). If the problem goes away, try compiling with optimization but without /Oa or /Ow.

    The following code can cause an aliasing problem:

    i = -100;
    while( i < 0 )
    {
         i += x + y;
         *p = i;
    }


    Without /Oa or /Ow, the compiler assumes that the assignment to *p can modify x or y, so it does not assume that x + y is constant for each iteration. If you specify /Oa or /Ow, the compiler assumes that modifying *p does not affect x or y and the calculation of x + y can be removed from the loop.


  • >>> Вот фрагмент кода который без volatile просто не компилируется: например метод locked::dec(volatile long& cnt);

    >
    > ME>Вот тебе минимальный код, который вопреки твоим словам скомпилируется:
    >
    > ME>
    > ME>long l;
    > ME>locked::dec(l);
    > ME>

    >
    > Нет, так как

    Что не так? Я тебе привел код, и он, вопреки твоим утвержедениям, компилируется.

    >
    > struct locked
    > {
    >   static long dec(volatile long& v)
    >   {
    >     return InterlockedDecrement(&v);
    >   }
    > }
    >


    И здесь без volatile прекрасно скомпилируется:
       static long dec(long& v)
       {
         return InterlockedDecrement(&v);
       }


    >>> Использование критической секции вокруг mutex для проверки флагов active и terminate было протестировано и признано неоправданным — потеря производительности.

    >>>
    >>> Попытка использовать голые (не volatile) флаги вызывала очень странный behavior.
    >
    > ME>Почему не использовались InterlockedCompareExchangeRelease для чтения значений разделяемых переменных?
    >
    > А какая разница? Там их тоже volatile нужно обяъвлять
    >
    >
    > PVOID InterlockedCompareExchangePointer (
    >   PVOID volatile *Destination,  // destination address
    >   PVOID Exchange,               // exchange value
    >   PVOID Comperand               // value to compare
    > );
    >

    >

    С какой это стати? По правилам языка С и C++ преобразование, которое "увеличивает" cv-квалификацию объекта, является неявным. Для обратного же преобразования нужен явный каст.

    Вот тебе примерчик:

    long l;
    long volatile* p1 = &l; // ok
    long const volatile* p2 = &l; // ok
    long* p3 = const_cast<long*>(p2); // cast required


    Thank you for testing your code with Comeau C/C++!
    Tell others about http://www.comeaucomputing.com/tryitout !
    
    Your Comeau C/C++ test results are as follows:
    
    Comeau C/C++ 4.3.3 (Aug  6 2003 15:13:37) for ONLINE_EVALUATION_BETA1
    Copyright 1988-2003 Comeau Computing.  All rights reserved.
    MODE:strict errors C++
    
    In strict mode, with -tused, Compile succeeded (but remember, the Comeau online compiler does not link).


    > Я пишу реальные многоплатформенные конструкции.

    > Чем меньше внешних платформо зависимых функций тем мне легче.
    >
    > volatile поддерживается и VC и GCC — т.е. это реальная платформонезависимость. Меня устраивает. И это работает.

    Ok, давай разбираться. Судя по типу HANDLE и макросу WINAPI, многоплатформенность в приведенном куске кода ограничивается платформой windoze. Допускаю, однако, что приведенный класс thread_pool используется в качестве (только) win32 pimpl (так как нет наследования от интерфейса) в платформенно-независимом классе thread_pool or whatever.

    Для платформы windoze у нас имеется следующая документация (подразумевается IA32):
    1. Compiler documentation. Visual Studio в своей док-ции документирует свое implementation defined поведение volatile:

      ... the system always reads the current value of a volatile object at the point it is requested...

      So far so good. Также там говорится, что

      The volatile keyword is a type qualifier used to declare that an object can be modified in the program by something such as the operating system, the hardware, or a concurrently executing thread.

      Слов required/mandatory или даже recommended/advised мы здесь не встречаем.
    2. Документация к API, в частности MSDN: DLLs, Processes, and Threads. Требования или даже рекоммендации использовать volatile shared variables мы здесь также не находим.
    3. Док-ция к процессору, здесь — IA-32 Intel® Architecture Software Developer's Manual Volume 3: System Programming Guide. Здесь нам черным по белому пишут в §7.2.4:

      It is recommended that software written to run on Pentium 4, Intel Xeon, and P6 family processors assume the processor-ordering model or a weaker memory-ordering model. The Pentium 4, Intel Xeon, and P6 family processors do not implement a strong memory-ordering model, except when using the UC memory type. Despite the fact that Pentium 4, Intel Xeon, and P6 family processors support processor ordering, Intel does not guarantee that future processors will support this model. To make software portable to future processors, it is recommended that operating systems provide critical region and resource control constructs and API s (application program interfaces) based on I/O, locking, and/or serializing instructions be used to synchronize access to shared areas of memory in multiple-processor systems. Also, software should not depend on processor ordering in situations where the system hardware does not support this memory-ordering model.


    На основе чего ты вывел, что твой volatile переносим и достаточен для обеспечения синхронизации при чтении разделяемой между потоками переменной? Так же, ты наплевал на предупреждения и рекоммендации Intel'a по написанию портабельного кода.

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

    >
    > Знаешь, Макс, в моем багаже законченных продуктов

    Это уже не аргумент и оффтопик.

    > есть например специализированный FTP сервер который работает без перезагрузки машины

    > уже 14 месяцев с очень хорошим трафиком. Это я к тому что я примерно представляю как программировать multithreaded applications.

    Ok, давай меряться пиписьками. В моем багаже softswitch — VoIP сервер разруливающий пару тысяч соединений в секунду в real-time в одном единственном потоке (разбор ASN.1 BER запросов, обращения к базе oracle, etc..). Ты тут особо упираешь на производительность, но многопоточные приложения даже теоретически не могут обрабатывать больше соединений, чем однопоточные, хотя бы потому, что они привносят в приложения два из четырех основных performance killers: context switching и lock contention. Подробности: http://www.kegel.com/c10k.html , http://pl.atyp.us/content/tech/servers.html

    []

    >>> Вообще когда multithreading нечто начинает вести себя странно — ищи где ты забыл поставить volatile.

    >
    > ME>У меня есть чудесная мантра со 100% эффективностью от таких проблем:
    > ME>

    > ME>Забудь про volatile, когда ты используешь multithreading.
    > ME>

    >
    > Я не говорю что без volatile нельзя написать multihreading код.
    > Я говорю — volatile есть, описан в стандарте языка,

    Вот только эффекты от использования volatile are implementation defined. Стандарт здесь никаких гарантий не дает.

    > поддерживается нужными мне компиляторами и реально помогает мне писать эффективный код (простой, надежный, human readable).


    Но только не портабельный.

    > Естесственно ты волен и вправе остваться при своем мнении. Только

    > вот эту вот максиму "Забудь про volatile, когда ты используешь multithreading" ты лучше не пой на интервью по С++.
    > Тебя сразу спросят про как вызвать тогда InterlockedIncrement и тебе нужно будет долго объяснять "что конкретно ты имеешь ввиду".

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

    > Вот например как реализуются barriers c помощью volatile переменных:

    >
    > http://docs.hp.com/en/B3909-90003/apas04.html

    В заголовке Using pthreads. Авторы стандарта pthreads (в частности, уже процитированный здесь David Butenhof) нам говорят, что для pthreads volatile избыточен. Либо тот кусок кода предназначен для компилятора, который не удовлетворяет требованиям pthreads, либо автор кода не был знаком со стандартом pthreads.

    --
    Maxim Yegorushkin
    Posted via RSDN NNTP Server 1.9
    Re[6]: volatile у переменной класса
    От: Mr. None Россия http://mrnone.blogspot.com
    Дата: 23.06.05 03:17
    Оценка: +1 :))) :)))
    Здравствуйте, Alex Alexandrov, Вы писали:

    AA>Здравствуйте, Mr. None, Вы писали:


    MN>>А если в подробностях ? Может статью на эту тему, а то ощущается некая нехватка собранной и структурирванной информации на эту тему, причём на русском языке (помните главную идеологию RSDN — обширный портал для руско-говорящих программистов )


    AA>Я подумаю над этим. Макс, порецензируешь, если что?


    Процензирует, процензирует!!! ДА-А-ЁШЬ СТА-АТЬЮ!!!! Восстановим репутацию родного города, изрядно подмоченную господином Губановым ...
    Компьютер сделает всё, что вы ему скажете, но это может сильно отличаться от того, что вы имели в виду.
    Re[5]: volatile у переменной класса
    От: Alex Alexandrov США  
    Дата: 22.06.05 18:35
    Оценка: 55 (5) +1
    Здравствуйте, Mr. None, Вы писали:

    MN>А если в подробностях ? Может статью на эту тему, а то ощущается некая нехватка собранной и структурирванной информации на эту тему, причём на русском языке (помните главную идеологию RSDN — обширный портал для руско-говорящих программистов )


    Я подумаю над этим. Макс, порецензируешь, если что?

    MN>Вопрос.

    MN>Как-то в одной из веток (возможно даже в этой — сейчас уже не найду) проскакивало такое заявление: поскольку явных механизмов установки барьера памяти в C++ нет, то неявным является вызов обычной функции (вроде как компилятор должен обеспечить генерацию такого кода). То есть насколько я понял вызов функции (возможно специально оформленной — естественно inline функций это не касается ) гарантировано заставляет процессор перечитывать даные из памяти и тем самым решается проблема переупорядочивании комманд. Насколько это утверждение близко к действительности, из чего оно следует и можно ли его принять на вооружение, как гарантированное средство? Вызов каких именно функции приводит к таком поведению или всех кроме подставляемых?

    Не стоит путать барьеры компилятора и барьеры памяти.

    Барьер компилятора не имеет никакого отношения к процессору. Условно говоря, для компилятора регистры процессора являются этаким кэшем нулевого уровня — он помещает в них локальные или глобальные данные для ускорения работы с ними. Одним из основных свойств кэша является время жизни в нем данных, т.е. время жизни соответствия кэшированных данных и их оригинала. Так вот барьер компиляции разрывает эту связь, вынуждая компилятор перезагрузить данные в регистры из памяти. Таким барьером является либо применение спецификатора volatile при объявлении переменной (в этом случае компилятор не имеет права кэшировать эту ячейку в регистре, он может это делать только на малое время и только если машинную инструкцию иным образом исполнить не получается), либо вызов внешней функции, т.е. функции, которая находится в другой единице компиляции и про которую компилятор, таким образом, не знает какие регистры могли измениться во время работы этой функции.

    Барьер процессора — совершенно другая штука. Современные процессоры (не x86, но Итаниум и какие-то еще) могут (не могут as in умеют, а могут as in позволяют себе) переупорядочивать инструкции записи в память. Т.е. мы выполняем код

    * записать число 1 в ячейку памяти A
    * записать число 2 в ячейку памяти B
    * записать число 3 в ячейку памяти С


    но внешний наблюдатель может увидеть эти обновления в любой из 6 перестановок. Для упорядочивания этого процесса на процессорах с таким свойствами имеются специальные инструкции барьеров. Барьер может быть с одной из следующих семантик: acquire, release или full. Ссылки на материалы по этому есть в ветке.

    Оба барьера необходимы для правильной работы в многопроцессорной среде при простом доступе к памяти (без использования примитивов синхронизации или атомарных инструкций — например, в многократно рассмотренном примере с глобальной булевой переменной). Именно поэтому в общем случае просто volatile недостаточно. Хотя есть частные случаи, когда его хватит:

    1. На x86, поскольку здесь нет процессорного переупорядочивания.
    2. Компилятор может знать о необходимости генерации процессорного барьера вдобавок к своему. Например, у Intel Compiler для Itanium есть опция /Qserialize-volatile. По умолчанию, правда, выключена.

    Но самый надежный способ — все-таки примитивы синхронизации и атомарные Interlocked* функции. Как жаль, правда, что в Posix нет аналогов Interlocked*. Понимаю, что дань независимости от конкретных возможностей процессоров, но все равно жаль...
    ... << RSDN@Home 1.1.4 beta 7 rev. 447>>
    It's kind of fun to do the impossible (Walt Disney)
    Re[18]: volatile у переменной класса
    От: achp  
    Дата: 18.01.05 19:50
    Оценка: 29 (4) +1 :)
    Здравствуйте, emusic, Вы писали:

    A>>Хм... Если есть барьер, то зачем volatile?


    E>Бааалин. Глухой телефон Кто обещал, что барьер можно специфицировать на конкретный объект? Если на каждый объект сделать функцию, которая обеспечивает сливание его в память на одном процессоре и всасывание в другом — разумеется, компилятор после выполнения этой функции перечитает любую часть объекта из памяти, ибо в функцию будет передаваться неконстантная ссылка


    Причем здесь это? Прохождение барьера всегда связано с вызовом внешней функции. Объект, к которому возможно обращение из нескольких потоков — либо глобальный, либо к нему ранее были созданы пути доступа, которые компилятор отследить не в силах. Следовательно, компилятор обязан предполагать возможность изменения данных объектов.

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

    По мне так это несильно отличается от вот такого:

    int f()
    {
        char const* const p = "aaa";
        *const_cast<char*>(p) = 'b';
        const_cast<char const*&>(p) = p + 1;
    }


    Если же барьер не обеспечивает синхронизации памяти между процессорами, — ну тут уж извиняйте — никакое volatile вам не поможит.

    E>А если барьер неспецифичный, вроде KeMemoryBarrier в виндовом ядре? Как объяснить компилятору, что после вызова некоторой функции без аргументов последнее известное значение объекта уже нельзя считать валидным? Разумеется, если не применять глубокой оптимизации — компилятор будет осторожничать и перечитывать после каждого вызова неизвестной ему функции. Указание volatile для разделяемых объектов позволит ему максимально оптимизировать остальные объекты. Если охота еще и оптимизации разделяемых объектов — значит, нужны специфичные барьерные примитивы на каждый разделяемый объект.


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

    Разумеется, если ставить перед собой такие чисто практические задачи, то Вы совершенно правы.
    Я кончил, джентльмены, мне остается только поблагодарить вас за внимание.
    Re: volatile у переменной класса
    От: MaximE Великобритания  
    Дата: 09.01.05 18:55
    Оценка: 9 (1) +1 -4
    Vet wrote:

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

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

    Рихтер ошибался.

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

    --
    Maxim Yegorushkin
    Posted via RSDN NNTP Server 1.9
    Re[8]: Изменение errno
    От: MaximE Великобритания  
    Дата: 20.01.05 12:23
    Оценка: -1 :))) :))
    MaximE wrote:

    >

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

    ... или признаем твою неправоту по таймауту

    --
    Maxim Yegorushkin
    Posted via RSDN NNTP Server 1.9
    Re[3]: volatile у переменной класса
    От: Alex Alexandrov США  
    Дата: 21.06.05 20:06
    Оценка: 48 (3) +2
    Здравствуйте, <Аноним>, Вы писали:

    А>Если переменная не объявлена как volatile то цикл

    А>while(!m_bDone); будет всю жизнь крутиться. Так как компилятор не дурак. Он один раз прочтет m_bDone в регистр (кэш процессора) и потом каждый раз будет его проверять. И то что m_bDone уже давно была установлена другим потоком никогда не узнает.

    А>Если переменая объявлена как volatile то компилятору это команда что каждый раз перед обращением к этой переменной её нужно считать из памяти.


    А>======================================================

    А>И мютексы не нужны, и volatile нужны.

    Ох, зря эту ветку подняли... Рекомендую прочитать все перед высказыванием мыслей.

    Вкратце:

    1. Синхронизация через глобальную переменную без использования примитивов синхронизации или атомарных операций в общем случае некорректна. Казалось бы, какие проблемы могут быть в случае простого применения булевой переменной volatile? Ведь она либо есть, либо ее нет! Могут. Если потоки будут исполняться на разных процессорах одновременно, и процессор обладает способностью и желанием переупорядочивать операции чтения-записи в память, то второй процессор может увидеть изменения не в том порядке, в котором он ожидает. В частности, флажок может быть увиден установленным перед тем, как изменятся синхронизируемые таким способом данные (ой-ой-ой...). Так что volatile недостаточен.

    2. Как только вы вставляете в свой многопоточный код вызовы функций синхронизации WaitFor... или Interlocked... они начинают служить барьером времени компиляции для компилятора, форсируя его перезагружать глобальные переменные в регистры процессора, поскольку вызовы этих функций для компилятора — черный ящик и он не может делать предположений о том, меняют они содержимое регистров или нет. Соответственно, WaitFor.../Interlocked... служит заодно двусторонним барьером памяти для процессора.

    3. Таким образом, при использовании функций синхронизации, что highly appreciated, можно обойтись без volatile. Главным аргументом сторонников volatile в ветке было возможное "поумнение" компилятора, при котором он вдруг сможет понять, что регистры на самом деле функциями синхронизации не затрагивались и, значит, регистры перезагружать нельзя. Честно говоря, не уверен, что это произойдет когда-нибудь.
    ... << RSDN@Home 1.1.4 beta 7 rev. 447>>
    It's kind of fun to do the impossible (Walt Disney)
    Re[19]: [2]: : volatile: а можно примеры?
    От: MaximE Великобритания  
    Дата: 24.01.05 20:34
    Оценка: 32 (4)
    c-smile wrote:

    []

    > Ты пойми, никакого формального же описания "барьеров" в документации VC++ просто нет. Собственно как и ни в каком другом компиляторе.

    > Единственное что есть это volatile.

    Нашел немного.

    http://www.microsoft.com/whdc/driver/kernel/MP_issues.mspx

    [q]The volatile Keyword

    The volatile keyword in C indicates that the value associated with a variable can be changed by something outside the control of the current thread.
    The compiler reads the value of a volatile variable from memory each time the variable is referenced and writes the value of the variable to memory each time it is assigned. Without the volatile keyword, the compiler might optimize access to the variable by combining read or write operations or by reordering references to the variable in code.
    ...
    Details of how to implement the volatile keyword are not specified in the ANSI language standards, but are left to compiler developers. Therefore, implementations may vary from compiler to compiler. Never assume that every C compiler—or even every version of a single manufacturer’s C compiler—implements volatile in the same way.
    The Microsoft C compiler generates code for each assignment to or reference of a volatile variable, even if the code appears to have no effect. If you declare a variable as volatile, the compiler considers it volatile for the lifetime of the variable. You can also cast a single reference as volatile; in this case, the compiler is guaranteed to generate code for that reference only.
    ...
    If you look at the sample drivers shipped with the Windows DDK, you will see that volatile appears infrequently. In general, volatile is of limited use in driver code for the following reasons:
    • Using volatile prevents optimization only of the volatile variables themselves. It does not prevent optimizations of nonvolatile variables relative to volatile variables. For example, a write to a nonvolatile variable that precedes a read from a volatile variable in the source code might be moved to execute after the read.
    • Using volatile does not prevent the reordering of instructions by the processor hardware.
    • Using volatile correctly is not enough on a multiprocessor system to guarantee that all CPUs see memory accesses in the same order.
    Windows synchronization mechanisms are more useful in preventing all these potential problems.

    ...
    Windows Synchronization Mechanisms
    ...
    • The InterlockedXxx routines perform common arithmetic and logical operations atomically, ensuring correct results on multiprocessor systems. Whenever possible, drivers should use these routines because they are fast. Most of them are native processor instructions that are implemented inline by the compiler and can be called at any IRQL.
    ...
    Memory Barriers and Hardware Reordering
    In certain situations on some hardware architectures, the processor can reorder read and write instructions. Furthermore, on multiprocessor architectures, the sequence in which read and write operations are executed can appear different from the perspective of different processors. To prevent hardware reordering, the executable code must contain memory barriers.
    If your driver uses only the standard Windows locking mechanisms, you don’t need to be concerned about hardware reordering or memory barriers. All of the standard Windows locking mechanisms (spin locks, mutexes, kernel events, and resources managed by the executive resource package) protect against processor reordering by inserting memory barriers where required in executable code. So do the InterlockedXxx and ExInterlockedXxx functions.
    This feature is an important reason to use the Windows mechanisms and to avoid creating your own locks. As a general rule, a driver should never create its own locks except in the rare situations where it has special requirements that make using the Windows mechanisms impractical or undesirable. Driver-created locks must insert memory barriers to prevent hardware reordering in certain conditions. These conditions can be difficult to detect and the problems resulting from them can be extremely tricky to debug.
    ...
    [/q]

    И на закуску сладенькое фанатам volatile:

    Memory Barrier Semantics
    A memory barrier is a processor instruction that preserves the ordering of read and/or write operations from the perspective of any other processor. Memory barriers include processor instructions with acquire, release, and fence semantics. These semantics describe the order in which results of an operation become visible.
    • Acquire semantics mean that the results of the operation are visible before the results of any operation that appears after it in code.
    • Release semantics mean that the results of the operation are visible after the results of any operation that appears before it in code.
    • Fence semantics combine acquire and release semantics. The results of an operation with fence semantics are visible before those of any operation that appears after it in code and after those of any operation that appears before it.
    ...
    On x86 and x64-based hardware (including AMD64 and the Intel Extended Memory 64 Technology), the InterlockedXxx and ExInterlockedXxx functions have both acquire and release semantics by default. The Intel Itanium architecture, however, can execute operations that have either acquire or release semantics (and not both) faster than those that have both. On Windows “Longhorn,” Microsoft plans to provide versions of the InterlockedXxx and ExInterlockedXxx functions that support either acquire or release semantics.
    In addition, Microsoft CL 14.0.0 and later versions tighten the restrictions on the types of reordering that can occur around volatile variables. In these compilers, reads from volatile locations are treated as acquires and writes to volatile locations are treated as releases on hardware architectures that support these semantics.


    --
    Maxim Yegorushkin
    Posted via RSDN NNTP Server 1.9
    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[5]: [2]: : volatile: а можно примеры?
    От: eao197 Беларусь http://eao197.blogspot.com
    Дата: 18.01.05 09:59
    Оценка: 20 (3) +1
    Здравствуйте, Шахтер, Вы писали:

    Ш>Они уже приведены.


    То, что я видел выше нельзя назвать примерами реальных проектов. Это небольшие тестовые программки, которые дополнены комментариями типа "вот когда-нибудь, когда придут крутые-крутые компиляторы, которые увидят, как работают WaitForSingleObject/pthread_mutex_wait, вот тогда...". И еще говорят, что компилятор справедливо опасается оптимизировать доступ к переменным, если перед этим были сделалы какие-то внешние вызовы.

    Как мне кажется, довольно характерный пример псевдокода по работе о общими данными в многопоточных приложениях выглядит так:
    // Кто-то, что-то готовит.
    lock();
    ...
    flag = ready;
    unlock();
    
    // Кто-то, что-то ожидает.
    while( true )
        lock();
        if( ready != flag )
            unlock();
        else
            ...
            ready = not_ready;
            unlock();

    Причем как раз доступ к общим данным (в данном случае, flag) производиться рядышком с использованием синхронизирующих примитивов.

    Из того, что я прочитал, я сделал вывод, что компилятор не будет оптимизировать доступ к общим данным, если рядом есть вызов синхронизирующего примитива (просто потому, что компилятор будет считать этот вызов вызовом с побочными эфектами). Компиляторы не делают такой оптимизации сейчас. И я сомневаюсь, что они будут делать ее в будущем. Хотя бы из-за соображений совместимости.

    Поэтому пока я не считаю нужным делать рефакторинг своего кода и вставлять volatile туда, где его не было. И я не увидел пока реальных примеров из жизни, которые заставили бы меня это сделать. А было бы полезно увидеть (не только мне), если такие примеры имели место быть.
    ... << RSDN@Home 1.1.4 beta 3 rev. 185>>


    SObjectizer: <микро>Агентно-ориентированное программирование на C++.
    Re[5]: volatile у переменной класса
    От: c-smile Канада http://terrainformatica.com
    Дата: 10.01.05 19:08
    Оценка: 16 (2) :))
    Здравствуйте, MaximE, Вы писали:

    ME>Еще раз — volatile абсолютно бесполезен для multithreading.


    "Зуб даешь?"
    Re[6]: volatile у переменной класса
    От: MaximE Великобритания  
    Дата: 10.01.05 19:12
    Оценка: 14 (1) :)))
    c-smile wrote:

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

    >
    > ME>Еще раз — volatile абсолютно бесполезен для multithreading.
    >
    > "Зуб даешь?"

    mlja budu

    --
    Maxim Yegorushkin
    Posted via RSDN NNTP Server 1.9
    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[13]: volatile у переменной класса
    От: Шахтер Интернет  
    Дата: 15.01.05 13:16
    Оценка: 3 (1) +2 :)
    Здравствуйте, MaximE, Вы писали:

    ME>Шахтер wrote:


    >> ME>Я скомпилировал следующий код на VC71 и Intel 8 с максимальными настройками оптимизации, с LTCG/IPO и без. Во всех четырех случаях при чтении переменная не кэшировалась, неважно, volatile ли была переменная или нет.

    >>
    >> Ты не совсем прав в данном случае. Нет никаких гарантий, что подобное поведение сохраниться в будующем. В этом примере компилятор не смог оценить побочные эффекты от вызова Sleep, поэтому и перечитал переменную из памяти. А вот теперь уберем Sleep. И получим звездец.

    ME>Ты хочешь сказать, что добавим volatile — и все ok?


    Да. Именно для этого это ключевое слово и предназнчается.

    ME>Чтение из памяти на текущих процессорах Intel гарантировано прочитает актуальное значение, даже если память была изменена в кэше другого процессора, т.к. Intel для текущих процессоров применяет cache snooping. ...


    А какое это отношение имеет к обсуждаемому вопросу? volatile -- это средство ограничения оптимизации кода. Пример того, как оно работает, был приведён выше. К тому, что происходит в процессоре, это не имеет никакого отношения.
    ... << RSDN@Home 1.1.0 stable >>
    В XXI век с CCore.
    Копай Нео, копай -- летать научишься. © Matrix. Парадоксы
    Re[13]: [2]: : volatile: а можно примеры?
    От: eao197 Беларусь http://eao197.blogspot.com
    Дата: 21.01.05 09:24
    Оценка: 2 (2) +1 :)
    Здравствуйте, c-smile, Вы писали:

    CS>Знаешь, Макс, в моем багаже законченных продуктов

    CS>есть например специализированный FTP сервер который работает без перезагрузки машины
    CS>уже 14 месяцев с очень хорошим трафиком. Это я к тому что я примерно представляю как программировать multithreaded applications.

    CS>И кстати обрати внимание что тебе здесь оппонируют люди которые *реально* занимаются multithreading. emusic (респект) например.


    Ну вот, уже и до этого дошло.
    Для того, чтобы я не показался случайным в multithreading человеком, который по незнанию выступает заодно с MaximE, хочу сказать, что в нашей компании эксплуатируется несколько программных комплексов, которые исключительно на многопоточности и работают. Где потоки готовят данные для других потоков, передают их через очереди сообщений, результаты обработки подхватывают третьи потоки, все это фиксируется/транслируется четвертыми потоками и т.д. Короче поток на потоке и потоком погоняет. Все это работает 24x7, уже не первый год, с остановками только на переконфигурирование. На платформах Windows и Linux, готовимся к переходу на HPNonStop. Некоторые из этих комплексов обрабатывают более миллиона транзакций в месяц. И все это на собственных библиотеках поддержки многопоточности.

    Я действительно не эрудированный человек, много не знаю, в разработке pthreads или подобных системных вещей не участвовал, со стандартом C++ знаком поверхносно и вообще работа задавила, учиться некогда. Но с многопоточностью сталкиваюсь каждый день. И пока не видел, чтобы мои действия без volatile приводили к проблемам. Но если вероятность этих проблем есть, даже с соблюдением таких методов предосторожности, как синхронизирующие примитивы и нормального уровня оптимизация, то хотелось бы сделать правильные выводы.

    Пока я вижу две точки зрения:

    1. volatile нужен, т.к. в стандарте C++ не определено поведение в многопоточности. Поэтому компилятор имеет право проводить агрессивную оптимизацию. Поэтому, если не объявить переменную volatile, новое значение этой переменной из другого потока можно не увидеть, т.к. ее значение может быть закэшированно. Однако, есть "внешние вызовы", которые могут быть с побочными эффектами. Из-за них компилятор не использует черезмерную агрессивную оптимизацию (если его об этом не просят). Но следует считаться с тем, что грядут очень умные компиляторы и линкеры, которые способны прооптимизировать весь код, даже тот, который находиться в obj, static-lib и dll. А есть еще SMP-архитектуры, хитрые процессоры с переупорядочением инструкций и спекулятивными вычислениями, предсказаниями ветвлений и т.д. Получается, что без volatile вообще /censored/!

    Я бы назвал это теоритической точкой зрения. С ней бесполезно спорить, т.к. она логична и, с теоритической точки зрения, правильна. Не буду пытаться.

    Но, и это очень большое но:

    2. Мультипоточный код без volatile работает. Прекрасно работает. На разных платформах и разных поколениях разных комиляторов.

    Это я бы назвал практической точкой зрения. С ней бесполезно спорить, т.к. это факт.

    Соответственно, истина где-то в стороне от этих двух точек зрения.

    И я бы хотел надеяться, что сработает закон "покупатель всегда прав". Если мне будут предлагать купить компилятор, который за счет глобальной оптимизации увеличит производительность моих программ вдвое, но при этом мне придется переписывать, перетестировать уже готовые приложения, то я, вероятно, скажу нет, не куплю. Т.к. дешевле купить вдвое более мощную платформу, чем переписать уже существующий код. И если мне говорят, что в стандарте ничего про многопоточность не сказано и, поэтому нужно использовать volatile, то я скажу: "А стандарт-то дырявый! Сделайте новый стандарт. В котором бы использование volatile не требовалось бы. Иначе я ваш язык использовать не буду и компиляторы покупать не буду, т.к. я покупатель. Я должен быть прав /какой знак здесь поставить, восклицательный или вопросительный/".


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

    ---
    P.S.

    MaximE, мы то знаем, что мы правы
    ... << RSDN@Home 1.1.4 beta 3 rev. 185>>


    SObjectizer: <микро>Агентно-ориентированное программирование на C++.
    Re[8]: volatile у переменной класса
    От: vanishing  
    Дата: 22.06.05 06:19
    Оценка: 2 (2) +2
    E>А что ему мешает их вставлять, интересно? Не вставляет — такова реализация. Но барьеры без volatile особого смысла не имеют. Если программа с глубокой оптимизацией и параллелизмом правильно работает без volatile — это либо недостатки компилятора, либо счастливое стечение обстоятельств.

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

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

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

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


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


    это не стечение обстоятельств : ). по опыту знаю, что на alpha, powerpc и xscale всё тоже корректно работает. просто это ведь очевидно. если в функцию примитива синхронизации передаётся указатель на переменную, то, какой бы ни была оптимизация в компиляторе, он просто обязан значение этой переменной сохранить в память, а затем уже вызывать функцию. дальнейшее — дело техники и специфичной для неё реализации примитива синхронизации. если же речь о глобальных переменных, то опять же. компилятор си (это особенность языка) не может знать, с какими именно ячейками в глобальной памяти будет работать та или иная функция, особенно, если речь идёт о вызове функции из другого модуля. поэтому все глобальные переменные, в том числе и static (чёрт ведь знает, куда что указывает) опять сохраняются в память. соответсвенно, после вызова функций, обращения к ним включают чтение из памяти.

    volatile был полезен, пока человечество искало подходы к многопоточному программированию. но сейчас, imho, от него никакой пользы. одно лишь смущение умов. лишние знания ограничивают свободу творчества. вот человек вместо того, чтобы творить. сидит и разбирается, а что же такое volatile есть.
    Re[19]: volatile у переменной класса
    От: emusic Франция https://software.muzychenko.net/ru
    Дата: 19.01.05 04:02
    Оценка: 20 (2) +1
    Здравствуйте, achp, Вы писали:

    A>Прохождение барьера всегда связано с вызовом внешней функции. Объект, к которому возможно обращение из нескольких потоков — либо глобальный, либо к нему ранее были созданы пути доступа, которые компилятор отследить не в силах. Следовательно, компилятор обязан предполагать возможность изменения данных объектов.


    Я дважды приводил два примера. Один — со статическим переменными/функциями, обращения к которым компилятор легко может отследить и установить, что, извне ни одна переменная не изменяется. Что в данном случае может удержать компилятор от оптимизации работы с этими переменными, и заставить его предполагать, что после вызова какой-то там внешней функции локальные для модуля статические переменные вдруг изменятся?

    Второй пример — с созданием динамического объекта, на который в каждый момент времени существует только один способный к разыменованию указатель. В рамках каждого потока, разумеется.

    A>Разумеется, это не касается случая, когда включена форсированная оптимизация. Ну, это уже ваш собственный выбор — у компилятора к услугам обманщиков вообще есть широчайший ассортимент способов устроить неопределенное поведение.


    Прошу показать мне место в описании ключей /Ow и /Oa компилятора MS VC++, где об этом говорится.

    A>По мне так это несильно отличается от вот такого:


    A>
    A>int f()
    A>{
    A>    char const* const p = "aaa";
    A>    *const_cast<char*>(p) = 'b';
    A>    const_cast<char const*&>(p) = p + 1;
    A>}
    A>


    Отличается принципиально. В силу того, что единственная языковая конструкция, применимая к multithreading — этот самый volatile. И почему-то компилятор, "обманутый" в моем примере ключом /Oa, при добавлении volatile к определению переменных вдруг начинает генерировать совершенно работоспособный код. Наверное, это случайность, да? А какие уточняющие спецификаторы нужно внести в вышеприведенный код, чтобы обманутый (уже без кавычек) компилятор сделал все правильно?

    A>Если же барьер не обеспечивает синхронизации памяти между процессорами, — ну тут уж извиняйте — никакое volatile вам не поможит.


    Разумеется. О чем я и говорил — что без volatile многопоточный код будет в общем случае некорректен, и все доводы противников volatile о том, что у них все работает опираются исключительно на совокупность частных случаев.

    A>В Си/Си++ как языке просто нет легальных средств для такой тонкой оптимизации.


    Не понял. Какие, по-Вашему, в Си/Си++ вообще есть "легальные средства для оптимизации"? Я не знаю ни одного В языке есть средства, которые могут помочь проводить оптимизацию, но и только. И которые с развитием техники оптимизации в компиляторах постепенно утрачивают значение — register давно стал бесполезен, арифметические операции ++/-- тоже давно перестали быть эффективнее прибавления/вычитания единицы.

    Собственно, меня вообще удивляет, почему следующее утверждение кто-то не согласен считать аксиомой: "До тех пор, пока в языке C++ не появится средств для указания наличия многопоточности, компилятор имеет право на любую оптимизацию, при которой сохраняется правильное поведение программы в однопоточном варианте". Аргументированных возражений никто до сих пор не привел. Единственное, что в C/C++ хотя бы косвенно указывает на какую-то асинхронность — это volatile.
    ... << RSDN@Home 1.1.4 beta 3 rev. 185>>
    Re[16]: volatile у переменной класса
    От: MaximE Великобритания  
    Дата: 16.01.05 10:00
    Оценка: 19 (3)
    c-smile wrote:

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

    >
    > ME>Весь мир давно заездил эту тему до дыр, только до rsdn прогрессивная мысль никак не доберется (.
    >
    > Макс, это уже не смешно.
    > Или давай технические спеки или ссылки на докуметнацию компиляторов.
    > Короче что-нибудь, но не ссылки на threads в дискуссиях ведущихся анонимными авторами.

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

    > "Весь мир давно заездил эту тему" ты имеешь ввиду себя и пару тройку "просвященных"?

    > Примерно 25% этого мира посещяет RSDN на котором мы видим "луч света в темном царстве" в твоем лице.

    Я так не думаю.

    > Чего ты уперся? volatile is a C++ keyword. Period.


    Это несет ровно такой же смысл, как сказать: "Земля — это планета. Точка."




    Мы обсуждаем здесь volatile и multithreading. С этим все согласны?

    Я приводил цитаты из док-ции Intel, где они явно рекоммендуют использовать синхронизацию для доступа к shared data. Этого было не достаточно?

    Мнение Alexander Terekhov'а (кроме него и Butenhof'a лучшие специалисты по threads мне неизвестны).

    http://groups-beta.google.com/group/comp.std.c/msg/ae49dc7a96c625f5

    There are (depending on how one breaks these things down) at least three
    independent issues here:


    1. Atomic access granularity
    2. Read/write ordering
    3. Memory coherency


    This discussion has been trying to address the three as if they were the
    same. They're not even connected. (Or, at best, only very loosely connected.)


    Most modern machines (yes, I should probably use quotes again) are designed
    for fast and efficient multiprocessing. The memory interconnect is the big
    bottleneck, and a lot of work has gone into streamlining the memory access
    and cache protocols. Memory accesses are usually made in "chunks" not
    necessarily related to the size of the data type. In general, a machine has a
    few "memory access types", very likely a smaller set than the set of
    instruction set types. Usually, only "memory access types" are atomic. On an
    Alpha EV4 and EV5, for example, the memory access types are 32-bit "words"
    and 64-bit "longwords". Smaller accesses require loading and masking a word
    or longword. While some machines might choose to hide the distinction between
    "memory types" and "instruction types", Alpha doesn't. To read a byte, you
    must load the enclosing word/longword, (I'll use "word" for convenience from
    now on), and use special instructions to mask/shift into the desired
    position.


    That's all fine, except when you get into concurrently executing entities
    (threads, or processes using shared memory), and one tries to STORE into the
    non-atomic field. To store such a field, you fetch the current word, shift &
    mask (field insert) your new data, and then write the word back. If another
    entity is simultaneously setting a different field in the same word, only ONE
    of the two will supply a new value for the entire word, including the other
    thread's field. Worse, a non-atomic field (e.g., a 16-bit short rather than a
    byte) might be split between two words. If it does, you can get into trouble
    even reading, because you have to read both words and combine them to create
    the short value you want. Some other thread might have changed one of the
    words between your two reads. That's "word tearing", and it means you've
    gotten the wrong data. Of course word tearing can happen on writes, too, in
    addition to the normal field access problems. Messy!


    Attempting to share information between concurrently executing instruction
    streams (that may be on separate processors) also requires read/write
    ordering. That is, if you set a flag to signal some change in state (e.g.,
    adding an item to a queue), you must be able to know that seeing the change
    in the flag means you can see the new queue item. Modern SMP memory systems
    frequently allow reordering of operations in the CPU to memory controller
    pipeline, for all sorts of reasons (including cache synchronization issues,
    speculative execution, etc.) So you may queue an item and then set a flag (or
    fill in the fields of a structure and then queue it), but have the data
    become visible to another processor in a different order. Unless you're
    communicating between concurrently executing entities, reordering doesn't
    affect you -- so it's a great performance tradeoff. But it means that when
    you require ordering, you need to do something extra. One common way to force
    ordering is a "memory barrier" instruction. On Alpha, for example, MB
    prevents memory operation reordering across the instruction. (One could
    consider a stream of memory requests in a pipe between the CPU and memory,
    which can be arbitrarily reordered for implementation convenience; but the
    reordering agent can't move anything past an "MB token".)


    And then we've got memory coherency. A "write-through" cache may invalidate
    other caches, and update main memory. But a "write-back" cache may not write
    into main memory for some time. Even if other caches are invalidated, the
    processors won't see the new value until it's written. That's OK, though, as
    long as both processors make proper use of memory barriers. The writer puts a
    memory barrier between writing the data and writing the flag (or pointer),
    and the reader puts a memory barrier between reading the flag/pointer and
    reading the data. Now, whenever the flag/pointer appears in memory, you know
    that the data to which it points is valid -- because you can't have read it
    before the flag, and the writer can't have written it after the flag.


    For more information without getting too deep into processor implementation
    details, see the section "Memory visibility between threads" in my book
    (Programming with POSIX Threads, web link in my .sig). Curt Schimmel's
    UNIX Systems for Modern Architectures (Addison-Wesley) has a section called
    "Other Memory Models" that describes the SPARC architecture's "Partial Store
    Ordering" (loose read/write ordering with memory barriers), though it doesn't
    address word tearing.

    ...

    The whole idea of RISC is *exactly* to make software more complex. That is, by
    simplifying the hardware, hardware designers can produce more stable designs that
    can be produced more quickly and with more advanced technology to result in faster
    hardware. The cost of this is more complicated software. Most of the complexity is
    hidden by the compiler -- but you can't necessarily hide everything. Remember that
    POSIX took advantage of some loopholes in the ANSI C specification around external
    calls to proclaim that you can do threaded programming in C without requiring
    expensive and awkward hacks like "volatile".
    Still, the interpretation of ANSI C
    semantics is stretched to the limit. The situation would be far better if a future
    version of ANSI C (and C++) *did* explicitly recognize the requirements of threaded
    programming.

    ...
    > However, I really believe that dataA and dataB should both be declared as
    > "volatile" to prevent the compiler from being too aggressive on it's
    > optimization. The mutex still doesn't guarantee that the compiler hasn't
    > cached the data in an internal register across a function call. My memory
    > isn't perfect, but I do think this bit me on IRIX.


    The existence of the mutex doesn't require this, but the semantics of POSIX and
    ANSI C do require it. Remember that you lock a mutex by calling a function, passing
    an address. While an extraordinarily aggressive C compiler with a global analyzer
    might be able to determine reliably that there's no way that call could access the
    data you're trying to protect, such a compiler is unlikely -- and, if it existed,
    it would simply violate POSIX 1003.1-1996, failing to support threads.


    You do NOT need volatile for threaded programming. You do need it when you share
    data between "main code" and signal handlers, or when sharing hardware registers
    with a device. In certain restricted situations, it MIGHT help when sharing
    unsynchronized data between threads (but don't count on it -- the semantics of
    "volatile" are too fuzzy). If you need volatile to share data, protected by POSIX
    synchronization objects, between threads, then your implementation is busted.


    ...

    > If you stick to a "natural machine word" that is declared as "volatile",
    > you do not absolutely need a mutex (in fact I've done it). Of course, there are
    > only certain cases where this works and shouldn't be done unless you really know
    > your hardware architecture and what you're doing! If you have a machine with a
    > lot of processors, unnecessarily locking mutexes can really kill parallelism.


    > I'll give one example where this might be used:



    > volatile int stop_flag = 0; /* assuming an int is atomic */


    > thread_1
    > {
    > /* bunch of code */


    > if some condition exists such that we wish to stop thread_2


    > stop_flag = 1;


    > /* more code — or not */
    > }


    > thread_2
    > {
    > while(1)
    > {
    > /* check if thread should stop */
    > if (stop_flag)
    > break;


    > /* do whatever is going on in this loop */
    > }
    > }


    > Of course, this assumes the hardware has some sort of cache coherency
    > mechanism. But I don't believe POSIX mutex's or memory barriers (as
    > defined for the DEC alpha) have any impact on cache coherency.


    If a machine has a cache, and has no mechanism for cache coherency, then it can't
    work as a multiprocessor.



    > The example is simplistic, but it should work on a vast majority of
    > systems. In fact the stop_flag could just as easily be a counter
    > of some sort as long as only one thread is modifying the counter...


    In some cases, yes, you can do this. But, especially with your "stop_flag",
    remember that, if you fail to use a mutex (or other POSIX-guaranteed memory
    coherence operation), a thread seeing stop_flag set CANNOT assume anything about
    other program state. Nor can you ensure that any thread will see the changed value
    of stop_flag in any particular bounded time -- because you've done nothing to
    ensure memory ordering, or coherency.


    And remember very carefully that bit about "as long as only one thread is
    modifying". You cannot assume that "volatile" will ever help you if two threads
    might modify the counter at the same time. On a RISC machine, "modify" still means
    load, modify, and store, and that's not atomic. You need special instructions to
    protect atomicity across that sequence (e.g., load-lock/store-conditional, or
    compare-and-swap).


    Am I trying to scare you? Yeah, sure, why not? If you really feel the need to do
    something like this, do yourself (and your project) the courtesy of being EXTREMELY
    frightened about it. Document it in extreme and deadly detail, and write that
    documentation as if you were competing with Stephen King for "best horror story of
    the year". I mean to the point that if someone takes over the project from you, and
    doesn't COMPLETELY understand the implications, they'll be so terrified of the risk
    that they'll rip out your optimizations and use real synchronization. Because this
    is just too dangerous to use without full understanding.



    There are ways to ensure memory ordering and coherency without using any POSIX
    synchronization mechanisms, on any machine that's capable of supporting POSIX
    semantics. It's just that you need to be really, really careful, and you need to be
    aware that you're writing extremely machine-specific (and therefore inherently
    non-portable) code. Some of this is "more portable" than others, but even the
    "fairly portable" variants (like your stop_flag) are subject to a wide range of
    risks. You need to be aware of them, and willing to accept them. Those who aren't
    willing to accept those risks, or don't feel inclined to study and fully understand
    the implications of each new platform to which they might wish to port, should
    stick with mutexes.


    http://groups-beta.google.com/group/comp.lang.c++/browse_frm/thread/82ea6195d505250c/ba4fc712e25a904b?q=volatile+nor+sufficient&amp;_done=%2Fgroups%3Fie%3Dutf-8%26oe%3Dutf-8%26q%3Dvolatile+nor+sufficient%26qt_s%3DSearch+Groups%26&amp;_doneTitle=Back+to+Search&amp;&amp;d#ba4fc712e25a904b

    In fact, though you've said you weren't intending to advocate direct access to
    any "volatile" variable without applying synchronization and casting away
    "volatile", your first Gadget::Wait example does precisely that, and is wildly
    incorrect and dangerously misleading. Compiler volatile semantics are not
    sufficient when sharing flag_ between threads, because the hardware, as well as
    the compiler, may reorder memory accesses arbitrarily, even with volatile. (Nor
    would a compiler implementation that issued memory barriers at each sequence
    point for volatile variables be sufficient, unless ALL data was volatile, which
    is impractical and unreasonably expansive.)


    Memory barriers must be applied where necessary on many architectures, and
    there is no standard or portable way to generate them. There is no excuse for a
    compiler to require both volatile AND memory barriers, because there's no
    excuse for a compiler to reorder memory access around its own memory barrier
    construct. (Usually either a compiler builtin such as Compaq C/C++ "__MB()" or
    an asm("mb") "pseudocall".) The standard and portable way to ensure memory
    consistency is to rely on the POSIX memory model, which is based solely on
    specific POSIX API calls rather than expensive and inappropriately defined
    language keywords or nonportable hardware instructions. A system or compiler
    that does not provide the proper memory model (without volatile) with proper
    use of the portable POSIX API calls does not conform to POSIX, and cannot be
    considered for serious threading work. Volatile is irrelevant.


    Entirely aside from the language issues, my point was simply that "volatile",
    and especially its association with threaded programming, has been an extremely
    confusing issue for many people. Simply using them together is going to cause
    even more confusion. The illusory promise of volatile will lead novices into
    trouble.


    In contradiction to your absurd statement that "writing multithread programs
    becomes impossible" without volatile, the intended C and C++ semantics
    associated with volatile are neither useful nor sufficient for threaded code.
    And it is WITH volatile, not without, that "the compiler wastes vast
    optimization opportunities", especially as the expense of meeting the volatile
    "contract" is of no benefit to threaded code.



    --
    Maxim Yegorushkin
    Posted via RSDN NNTP Server 1.9
    Re: volatile у переменной класса
    От: c-smile Канада http://terrainformatica.com
    Дата: 10.01.05 05:40
    Оценка: 18 (1) -2
    Здравствуйте, Vet, Вы писали:

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

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

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

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

    Да, обязательно, иначе оптимизатор тебе такого наворотит — не обрадуешься.

    The volatile keyword is a type qualifier used to declare that an object can be modified in the program by something other than statements, such as the operating system, the hardware, or a concurrently executing thread.


    Желательно еще установку этой переменной выполнять с помощью InterlockedExchange.
    Собственно так как эта функция объявлена как

    LONG InterlockedExchange(
      LPLONG volatile Target, // value to exchange
      LONG Value              // new value
    );


    без объявления volatile у тебя ничего и не получится.
    Re[9]: читаем про volatile
    От: elcste  
    Дата: 18.01.05 02:03
    Оценка: 13 (2) +1
    Здравствуйте, Seriously Serious, Вы писали:

    SS>Хочется увидеть аргументы против такого использования volatile


    Аргументы в основном сводятся к тому, что experienced multithreaded programmers, которых Александреску упоминает в статье, не станут читать дальше заглавия. Для завсегдатаев comp.programming.threads тема "volatile и multithreaded programming" — нечто вроде красной тряпки для быка. Те же, кто не обратил внимания на название, перестанут читать после примера в первом разделе, когда увидят, что автор ничего не знает о multithreaded programming. Наконец, самые стойкие дочитают до конца и поймут, что им предлагается "an abuse of the type system" (Джеймс Канце) с единственной целью: добиться неопределенного поведения (7.1.5.1/7).
    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[7]: [2]: : volatile: а можно примеры?
    От: eao197 Беларусь http://eao197.blogspot.com
    Дата: 19.01.05 08:42
    Оценка: 30 (1) +1
    Здравствуйте, Шахтер, Вы писали:

    E>>Из того, что я прочитал, я сделал вывод, что компилятор не будет оптимизировать доступ к общим данным, если рядом есть вызов синхронизирующего примитива (просто потому, что компилятор будет считать этот вызов вызовом с побочными эфектами).


    Ш>Не обязательно. Компилятор может иметь список well-known функций, побочные эффекты от которых он знает. Например, фирме Майкрософт ничего не стоит научить VC++ оценивать побочные эффекты от вызова функций из API Win32. Технически, оптимизатор от VC++ содержит всё необходимое для этого.


    Как раз таки тогда VC++ прекрасно поймет, что после вызова функций типа WaitFor*Object нужно осуществлять перечитывание значений переменных, т.к. эти функции явно могут приводить к возникновению побочных эффектов.

    E>>И я сомневаюсь, что они будут делать ее в будущем.


    Ш>Стандарт это не запрещает. Единственный 100% легальный метод гарантировать это на сегодня -- использовать volatile. Так что всё остальное -- на твой страх и риск.


    Вот здесь: Double-Checked Locking, Threads, Compiler Optimizations, and More Скот Мейерс показывает, что даже использование volatile не гарантирует ожидаемого эффекта в многопоточном приложении (даже при использовании примитивов синхронизации). И делает замечательный вывод:

    Bottom line: the road to thread-safe code isn't paved with volatile


    Ничего личного, Шахтер, но я более склонен согласиться с Мейерсом, чем с вами

    Ш>Нет никаких сображений совместимости с нелегальным кодом. Полно примеров, когда новые компиляторы отказываются компилировать код, который компилировался старыми компиляторами, но не удовлетворял стандарту.


    Думаю, что здесь не все так однозначно. Нынешний стандарт никак не определял особенностей и привязки к многопоточности. Что оставляло большое поле для реализации различных решений при создании многопоточных приложений. И отмахнуться от того, что 20% (цифра с потолка) написанных на C++ многопоточных приложений окажутся не совместимыми со следующим стандартом сейчас уже никто не сможет. А я подозреваю, что таких приложений гораздо больше.

    Поэтому я надеюсь, может быть, напрасно, что добавление в C++ стандарт поддержки многопоточности произойдет без необходимости использования модификатора volatile для всех разделяемых между потоками данных.
    ... << RSDN@Home 1.1.4 beta 3 rev. 185>>


    SObjectizer: <микро>Агентно-ориентированное программирование на C++.
    Re[12]: [2]: : volatile: а можно примеры?
    От: Andrew S Россия http://alchemy-lab.com
    Дата: 19.01.05 06:44
    Оценка: 18 (1) +1
    >> (x) Случай Vx,Ax. Может ли в этом случае компилятор закэшировать значение переменной? Имеются в виду как обычные, так и наиболее агрессивные настройки оптимизации.
    >> Итого, соотв, 4 варианта.

    ME>Не будет закэшировано во всех вариантах. (если, конечно, никто не применит ключ компиляции "компайлер, здесь нет никакого альясинга, мамой клянусь!")


    Заметьте, я говорил как про обычную, так и агрессивную оптимизацию. Итак, вы все-таки признаете, что при включенной агрессивной оптимизации возможны проблемы. Например, вычисление значение переменной заранее, и затем использование его после внешнего изменения этого значения (пример, кстати, вам привел emusic). В случае с простыми interlocked, это, конечно, довольно сложно представить (но наверняка придумать пример можно), но как только в дело вступают критические секции, которые никак не позиционируют себя по отношению к объекту, который охраняют, ситуация усложняется.

    Тогда немного переформулируем вопрос. При условии того, что для синхронизации используются стандартные функции\примитивы синхронизации, предоставляемые ОС, использование volatile в определении разделяемой переменной:

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

    Соответственно, выбрать можно любой из пунктов (или несколько сразу) + придумать свои вариант, ессно, обосновав ответ.
    Для себя я, как уже говорил, выбираю б), поскольку не вижу минусов при указании подобным переменным спецификатора volatile. Оптимизировать доступ к ним обычно и не требуется, а плюсы, хоть редко, но быть могут, как уже было показано. С вариантом с) я никогда не встречался.
    http://www.rusyaz.ru/pr — стараемся писАть по-русски
    Re[3]: volatile у переменной класса
    От: emusic Франция https://software.muzychenko.net/ru
    Дата: 10.01.05 13:48
    Оценка: 3 (1) +1
    Здравствуйте, MaximE, Вы писали:

    ME>c-smile wrote:


    >> The volatile keyword is a type qualifier used to declare that an object can be modified in the program by something other than statements, such as the operating system, the hardware, or a concurrently executing thread.

    >> [/q]

    ME>Это не так. Кусок не из стандарта, а наверное, из MSDN. Почитайте про sequence points.


    Sequence points — это вообще из другой оперы. Sequence point — место, где заканчиваются побочные эффекты, и не более того. Причем относится это исключительно к имеющему место "потоку выполнения", и к параллельным потокам отношения не имеет. А вот при наличии volatile при каждом обращении к такому объекту формируется sequence point. Прохождение sequence point отнюдь не гарантирует, что состояния всех объектов в этой точке будут непременно отражены в памяти — это гарантируется только для volatile-объектов.

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


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

    ME> После sequence points, компилятор обязан перечитывать значения переменных из памяти, неважно, volatile ли, const ли, или это переменная без cv-квалификатора


    С чего бы он вдруг стал обязан? Компилятор обязан лишь обеспечить последовательное выполнение заданных действий в рамках одного потока исполнения. Для взаимодействия с "внешними" процессами и существует volatile.

    Простейший пример:

    void f (int &a, int &b) {
      if (!a) {
        b = a;
      }
    }


    При включенной оптимизации многие компиляторы (например, VC++ 6.0) сгенерируют только один опрос переменной a — в проверке условия. Для присваивания будет сгенерирован явный нуль. Если к a добавить volatile — будет сгенерировано повторное чтение из памяти. И совершенно правильно.
    ... << RSDN@Home 1.1.4 beta 3 rev. 185>>
    Re: volatile: а можно примеры?
    От: eao197 Беларусь http://eao197.blogspot.com
    Дата: 17.01.05 09:53
    Оценка: 1 (1) :)
    Добрый день всем.

    С большим интересом прочитал развернувшуюся здесь дискуссию. Эта тема меня очень заинтересовала. Дело в том, что я использую многопоточность давно, еще года с 1996, под разными ОС (Win32, OS/2, Linux, FreeBSD, HP NonStop). Но про взаимосвязь между volatile и многопоточностью узнал впервые в этой ветке. Действительно, меньше знаешь -- крепче спишь.

    До сих пор программировал без volatile. В основном из-за того, что в далеких 90-х еще не все компиляторы поддерживали такие ключевые слова, как volatile, вот и привык его не использовать (т.к. драйверов на C++ на писал). Написанный мной код, к счастью, работал. Но, по стечению обстоятельств, только на однопроцессорных машинах. Был только один случай, когда одна из систем была установлена на двухпроцессорной машине под Win2K. И как раз там наблюдались странные сбои, которые прекращались после перекомпиляции проекта любым компилятором, отличным от VC6.0sp5 (Borland C++, MinGW, VC7.0). Тогда причину сбоев установить не удалось, т.к. после перехода на VC7.0, а затем VC7.1, сбоев не было.

    В связи с этим у меня вопрос: можно ли услышать/увидеть реальные примеры того, как в многопоточных приложениях обнаруживались проблемы из-за того, что не использовалось volatile? Именно реальные, хорошо бы с примерами, хотя бы псевдокода. И не драйверов или софта для работы с железом, а "прикладного" кода.

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

    Заранее спасибо.


    SObjectizer: <микро>Агентно-ориентированное программирование на C++.
    Re[2]: volatile у переменной класса
    От: c-smile Канада http://terrainformatica.com
    Дата: 10.01.05 19:02
    Оценка: -2
    Здравствуйте, MaximE, Вы писали:

    ME>Рихтер ошибался.


    ME>volatile не имеет никакого отношения к multithreading, поэтому его применение в этой ситуации не только бесполезно, но может быть и вредно, так как с volatile компилятор не сможет соптимизировтать доступ к этой переменной. Но если один из потоков изменяет переменную, синхронизация при помощи мютексов обязательна.


    Максим, я извиняюсь но вот эти твои высказывания неверны.

    Для установки значения переменной в другом потоке используетс InterlockedExchange
    На i386 это две инструкции lock и txchgl.

    Mutexes (критические секции) для асинхронной установки значения это скажем так дурной тон. EnterCriticalSection/LeaveCriticalSection это два раза полновесный вызов Scheduler что не способствует быстродействию никак.
    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[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[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[2]: volatile у переменной класса
    От: Tom Россия http://www.RSDN.ru
    Дата: 15.01.05 16:04
    Оценка: +1 -1
    Здравствуйте, MaximE, Вы писали:

    ME>Vet wrote:


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

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

    ME>Рихтер ошибался.


    ME>volatile не имеет никакого отношения к multithreading, поэтому его применение в этой ситуации не только бесполезно, но может быть и вредно, так как с volatile компилятор не сможет соптимизировтать доступ к этой переменной. Но если один из потоков изменяет переменную, синхронизация при помощи мютексов обязательна.


    ME>--

    ME>Maxim Yegorushkin

    Абсолютно неверный и опасный совет. Как раз volatile тут необходим, как в прочем и желательна защита обьекта при помощи примитивов синхронизации. volatile нужен дабы избежать лишней оптимизации (компилятор может моложить переменную в регистр, и защищая её или нет, но другой поток об том, что переменная изменилась — не узнает никогда, или несвоевременно)
    Народная мудрось
    всем все никому ничего(с).
    Re[8]: [2]: : volatile: а можно примеры?
    От: Odi$$ey Россия http://malgarr.blogspot.com/
    Дата: 18.01.05 05:43
    Оценка: +2
    Здравствуйте, MaximE, Вы писали:

    >> ME>Мой поинт был в том (если этого до сих пор непонятно уважаемому Шахтеру), что какой бы семантикой не обладал volatile, ее просто не достаточно для multithreading, и поэтому volatile бесполезен для multithreading.

    >>
    >> не вдаваясь в технические подробности, из "недостаточно" никак не может следовать "и поэтому ... бесполезен"

    ME>На этом основании ты хочешь объявить все написанное здесь ересью и провозгласить, что volatile необходим и достаточен для обеспечиния синхронизации при multithreading?


    ну, про то что "volatile необходим и достаточен" здесь вообще никто ни разу не сказал, пытались обосновать только, что "необходим",
    а вот "недостаточно" "и поэтому ... бесполезен" — это действительно ересь хотя бы с точки зрения формальной логики
    Re[8]: [2]: : volatile: а можно примеры?
    От: AndrewJD США  
    Дата: 18.01.05 10:26
    Оценка: +2
    Здравствуйте, MaximE, Вы писали:

    >> ME>Мой поинт был в том (если этого до сих пор непонятно уважаемому Шахтеру), что какой бы семантикой не обладал volatile, ее просто не достаточно для multithreading, и поэтому volatile бесполезен для multithreading.

    >>
    >> не вдаваясь в технические подробности, из "недостаточно" никак не может следовать "и поэтому ... бесполезен"

    ME>На этом основании ты хочешь объявить все написанное здесь ересью и провозгласить, что volatile необходим и достаточен для обеспечиния синхронизации при multithreading?


    volatile — необходимое (в ряде случаев), но не достаточное условие
    "For every complex problem, there is a solution that is simple, neat,
    and wrong."
    Re[15]: volatile у переменной класса
    От: MaximE Великобритания  
    Дата: 18.01.05 12:54
    Оценка: :))
    Tom wrote:

    > ME>Этот код — некорректный многопоточный код, так как он не применяет синхронизацию для доступа к переменной.

    >
    > А ты думаешь компилятор перестанет оптимизировать, если появиться синхронизация?

    Твое нежелание читать тред просто потрясает.

    --
    Maxim Yegorushkin
    Posted via RSDN NNTP Server 1.9
    Re[7]: volatile у переменной класса
    От: What Беларусь  
    Дата: 18.01.05 12:57
    Оценка: +1 :)
    Здравствуйте, MaximE, Вы писали:


    ME>Ok, ты работаешь над проектом. Менеджер спрашивает тебя, готов ли ты поставить свою зарплату, что твой многопоточный кусок кода, в котором ты не используешь ф-ций синхронизации, а полагаешься на "fuzzy" семантику volatile, заработает на не Intel SMP системе? Что ты ему ответишь?

    Ок, вот так согласен

    Еще раз — без привязки к конкретной платформе volatile абсолютно бесполезен для multithreading.

    ... << RSDN@Home 1.1.4 beta 3 rev. 185>>
    Re[2]: volatile у переменной класса
    От: Аноним  
    Дата: 20.06.05 21:29
    Оценка: +1 -1
    Здравствуйте, MaximE, Вы писали:

    ME>Рихтер ошибался.


    ME>volatile не имеет никакого отношения к multithreading, поэтому его применение в этой ситуации не только бесполезно, но может быть и вредно, так как с volatile компилятор не сможет соптимизировтать доступ к этой переменной. Но если один из потоков изменяет переменную, синхронизация при помощи мютексов обязательна.



    Тут Максим вы не правы. Рихтер не ошибался. И синхронизировать не обящательно. Всё от ситуации зависит.

    пример. Имеем два потока один чего то делает и по завершению операции устанавливает переменную m_bDone в true.
    второй поток пытается синхронизироваться с первым и крутит пустой цикл до тех пор пока m_bDone != true;

    Если переменная не объявлена как volatile то цикл
    while(!m_bDone); будет всю жизнь крутиться. Так как компилятор не дурак. Он один раз прочтет m_bDone в регистр (кэш процессора) и потом каждый раз будет его проверять. И то что m_bDone уже давно была установлена другим потоком никогда не узнает.

    Если переменая объявлена как volatile то компилятору это команда что каждый раз перед обращением к этой переменной её нужно считать из памяти.

    ======================================================
    И мютексы не нужны, и volatile нужны.


    George.
    Re[11]: volatile у переменной класса
    От: Шахтер Интернет  
    Дата: 15.01.05 03:18
    Оценка: 18 (1)
    Здравствуйте, MaximE, Вы писали:

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


    ME>[]


    E>>Если тебе удается успешно обходиться без volatile, одними примитивами — это не более, чем случайность. Весьма, впрочем, распространенная ввиду того, что нынешние оптимизаторы в большинстве случаев справедливо опасаются использовать кэшированные ранее значения после вызова неизвестной функции (тот самый aliasing, разговор о котором ты предпочел не развивать). Но, попадись такой код мощному оптимизатору, который не поленится проанализировать вызываемую функцию, или окажись примитивы синхронизации реализованными в более явном виде, этот код нормально работать перестанет. И неожиданным это будет лишь для тебя


    ME>Я скомпилировал следующий код на VC71 и Intel 8 с максимальными настройками оптимизации, с LTCG/IPO и без. Во всех четырех случаях при чтении переменная не кэшировалась, неважно, volatile ли была переменная или нет.


    Ты не совсем прав в данном случае. Нет никаких гарантий, что подобное поведение сохраниться в будующем. В этом примере компилятор не смог оценить побочные эффекты от вызова Sleep, поэтому и перечитал переменную из памяти. А вот теперь уберем Sleep. И получим звездец. И в будующем ситуация может стать аналогичной и с вызовом Sleep. Дело в том, что существует предложение о введении спецификатора для функций без побочных эффектов (pure). Если это будет реализовано и функция Sleep будет помечена как pure, то и её вызов не будет рассматриваться компилятором как могущий изменить переменную a, что приведёт к нежелательной оптимизации.

    volatile int sleep_var;
    
    void sleep(int n) // Побочные эффекты от этой функции компилятор может оценить. См. ниже, к чему это приводит.
     {
      sleep_var=n;
     
      for(; sleep_var ;sleep_var--);
     }
    
    long a;
    volatile long b;
    
    void f()
    {
        while(!a)
            sleep(20);
    }
    
    void g()
    {
        while(!b)
            sleep(20);
    }


    _TEXT    SEGMENT
    ?f@@YAXXZ PROC NEAR                    ; f, COMDAT
    
    ; 21   :     while(!a)
    
        mov    eax, DWORD PTR ?a@@3JA            ; a
        test    eax, eax
        jne    SHORT $L285
        mov    eax, 20                    ; 00000014H
        npad    2
    $L284:
    
    ; 22   :         sleep(20);
    
        mov    DWORD PTR ?sleep_var@@3HC, eax        ; sleep_var
        mov    ecx, DWORD PTR ?sleep_var@@3HC        ; sleep_var
        test    ecx, ecx
        je    SHORT $L284
        npad    1
    $L312:
        mov    ecx, DWORD PTR ?sleep_var@@3HC        ; sleep_var
        dec    ecx
        mov    DWORD PTR ?sleep_var@@3HC, ecx        ; sleep_var
        jne    SHORT $L312
    
    ; 21   :     while(!a)
    
        jmp    SHORT $L284
    $L285:
    
    ; 23   : }
    
        ret    0
    ?f@@YAXXZ ENDP                        ; f
    _TEXT    ENDS
    PUBLIC    ?g@@YAXXZ                    ; g
    ; Function compile flags: /Ogtpy
    ;    COMDAT ?g@@YAXXZ
    _TEXT    SEGMENT
    ?g@@YAXXZ PROC NEAR                    ; g, COMDAT
    
    ; 27   :     while(!b)
    
        mov    eax, DWORD PTR ?b@@3JC            ; b
        test    eax, eax
        jne    SHORT $L290
        mov    eax, 20                    ; 00000014H
        npad    2
    $L289:
    
    ; 28   :         sleep(20);
    
        mov    DWORD PTR ?sleep_var@@3HC, eax        ; sleep_var
        mov    ecx, DWORD PTR ?sleep_var@@3HC        ; sleep_var
        test    ecx, ecx
        je    SHORT $L326
        npad    1
    $L324:
        mov    ecx, DWORD PTR ?sleep_var@@3HC        ; sleep_var
        dec    ecx
        mov    DWORD PTR ?sleep_var@@3HC, ecx        ; sleep_var
        jne    SHORT $L324
    $L326:
        mov    ecx, DWORD PTR ?b@@3JC            ; b
        test    ecx, ecx
        je    SHORT $L289
    $L290:
    
    ; 29   : }
    
        ret    0
    ?g@@YAXXZ ENDP                        ; g
    _TEXT    ENDS
    ... << RSDN@Home 1.1.0 stable >>
    В XXI век с CCore.
    Копай Нео, копай -- летать научишься. © Matrix. Парадоксы
    Re[11]: volatile у переменной класса
    От: emusic Франция https://software.muzychenko.net/ru
    Дата: 19.01.05 07:08
    Оценка: 16 (1)
    Здравствуйте, MaximE, Вы писали:

    E>>POSIX — замкнутая система, спецификация которой охватывает и аппаратную часть, и саму программу, и окружение программы.


    ME>Правилнее было бы сказать, что win32 — это закрытая система. POSIX — открытая, можешь разработать и внести свои предложения на рассмотрение.


    POSIX — не закрытая, а замкнутая система. Это означает, что спецификация платформы, кроме аппаратных особенностей и программной среды, включает еще и требования к языку, в данном случае — C/C++. Чтобы соответствовать спецификации POSIX, компилятор обязан обеспечить условия взаимной видимости переменных в pthreads. Однако это вовсе не обязывает его обеспечивать их в случае организации параллелизма иными, нежели pthreads, способами. Намек понятен?

    ME>Я говорю про то, что я знаю.


    Нет, изначально ты высказывал именно всеобщие утверждения о "бесполезности и даже вредности" volatile. И лишь после того, как тебя приперли к стенке, ты начал ссылаться на POSIX — опять-таки распространяя эту частную (пусть и популярную) систему на все случаи жизни.

    ME> На мой взгляд, POSIX и win32 — самые распространенные. Если ты специалист в mac, dec или еще каких threads, можешь просветить.


    Да дело же не в конкретных платформах и не в конкретных же реализациях многопоточности. А в том, что, если мы хотим обеспечить максимальную переносимость кода — мы обязаны изначально снабдить каждую разделямую переменную спецификатором volatile — кроме тех переменных, которые везде и явно модифицируются специальными внешними функциями, вроде InterlockedXXX. Это минимум. Далее, в зависимости от платформы, нам придется либо ужесточать условия, добавляя к имеющемуся volatile примитивы типа критических секций и/или барьеров, либо ослаблять их, заменяя volatile на средства, гарантирующие на данной платформе взаимную видимость переменных.

    ME>Для меня POSIX и win32 — это 100% случаев.


    Это для тебя. Для кого-то, кроме BC 3.1 for DOS, ничего другого не существует Если уж на то пошло, то в оригинальном сообщении автор спрашивал, "есть ли необходимость делать разделяемую переменную volatile", а не "достаточно ли будет одного volatile" для нормальной работы. И ссылался при этом на Рихтера, из чего можно было сделать вывод, что он работает под Win32. А ты ему с места в карьер принялся доказывать "бесполезность и вредность" volatile, да еще и со ссылками на POSIX впоследствии

    ME>Еще раз: POSIX volatile не нужен. В MSDN я также не нашел упоминания, что им нужен volatile.


    То есть, тебе требуется именно явное указание на его нужность? Оговорки насчет "concurrently executing thread" в описании самого спецификатора volatile тебе недостаточно? Мда, тяжелый случай.
    ... << RSDN@Home 1.1.4 beta 3 rev. 185>>
    Re[5]: ужас
    От: MaximE Великобритания  
    Дата: 20.01.05 11:28
    Оценка: 12 (1)
    achp wrote:

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

    >
    > SS>А если ВСЕ функции станут прозрачными и компилятор будет ВСЁ держать в регистрах?
    >
    > Во-первых, из "прозрачности" ещё не следует, что можно "всё держать в регистрах". "Прозрачность", то есть доступность для компилятора тела данной функции, может позволить компилятору сделать вывод о том, какие объекты подвергаются модификации при её вызове, а какие — нет. А может и не позволить.
    >
    > Во-вторых, тогда барьеры (и многопоточность вообще) станут просто невозможны.

    Еще примерчик. Любая "непрозрачная" ф-ция может изменить errno. errno не объявлен 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[3]: Реальный пример использования volatile
    От: eao197 Беларусь http://eao197.blogspot.com
    Дата: 18.01.05 11:56
    Оценка: 9 (1)
    Здравствуйте, What, Вы писали:

    W>А зачем здесь синхронизация? Один поток пишет значение переменной, другой читает. Главное, чтобы значение было записано атомарно. Это в данном случае для x86 гарантируется.


    Боюсь, что именно из-за таких предположений весь сыр бор вокруг volatile и начался. Я считаю, что есть принципиальные вещи: выделеную память нужно освобождать, открытые файлы закрывать, после входа в критическую секцию нужно выйти оттуда, ..., когда одна нить читает то, что другая может переписать, то это нужно синхронизировать. Это вопрос принципа (с моей точки зрения). И если ему следовать, то:
    — мы не зависим от volatile или не volatile;
    — мы не зависим от аппаратной платформы (могут быть какие-нибудь специализированные процессоры, на которых извлечение одного байта из памяти может не быть атомарной операцией, а требовать дополнительных арифметических операций/сдвигов);
    — мы не зависим от типа данных. Сейчас у нас переменная go -- это bool. Завтра -- это long int, в котором указано, сколько итераций нам еще разрешают сделать. После завтра -- структура, в которой описывается, при каких условиях нужно выходить, а при каких условиях еще можно провести пару-тройку итераций.
    А все из-за того, что изначально мы защитились синхронизацией. И не надеялись на особенности конкретной платформы и конткретного компилятора.

    W>С другой стороны, а если бы рабочих потоков было, скажем, 4 вместо 1. И все читали бы одну и ту же переменную. Тогда использование синхронизации могло бы привести к ненужным потерям производительности.

    За безопасность в многопоточности нужно платить. Некоторые из-за безопасности на более медленные языки программирования переходят Из-за того, что лишний раз delete вызвать лень

    E>>Если бы вы использовали синхронизацию доступа к go, то volatile, наверняка, не потребовался бы.

    W>Наверняка, да, не потребовался бы.

    От тож!
    ... << RSDN@Home 1.1.4 beta 3 rev. 185>>


    SObjectizer: <микро>Агентно-ориентированное программирование на C++.
    Re[2]: Поведение C++ runtime
    От: Костя Ещенко Россия  
    Дата: 20.01.05 11:45
    Оценка: 8 (1)
    eao197 wrote:

    > Шутки-шутками, но допустим, я захотел, чтобы моя программа использовала мою функцию strlen. Я не описываю ее прототипа, т.к. он определен в <cstring>, просто прилинковываю к программе еще один obj или lib. Но задачей моей strlen, кроме основной работы, может быть, скажем сбор статистики. Или strlen помещает последнюю вычесленную длину в глобальную переменную, чтобы она была доступна без повторного обращения к strlen. Или кэширует адреса строк и их длины для того, чтобы повторно не вычислять длину той же самой строки. Для этого моя strlen модифицирует какие-либо глобальные данные. Которые могут быть определены даже в другой lib-е. Так вот мне интересно, имеет ли право компилятор, встретив где-то в коде strlen посчитать, что он все знает про эту функцию (она же из стандартной библиотеки) и оптимизировать все, что находится вокруг нее? Причем меня волнует компилятор, который, пока, делает основную оптимизацию, а не линкер, который-то явно будет знать, что strlen не стандартная.

    >
    > Пример с strlen может быть и притянут с потолка. Но почему такого не может быть с malloc/free/realloc? Ведь предоставление своих версий глобальных new и delete является распространенной практикой.

    Объявление/определение функции из стандартной библиотеки С, например strlen, в глобальном или ::std неймспейсах с внешней компоновкой приводит к ub. Это значит что можно создать strlen только либо в своем неймспейсе, либо локальную, либо статическую (с внутренней компоновкой).
    В 17.4.3 вообще куча страшилок, но new/delete и некоторые другие специально разрешено переопределять.
    Posted via RSDN NNTP Server 1.9
    На самом деле, люди не читают газеты, они принимают их каждое утро, так же как ванну. ©Маршалл Мак-Льюэн
    Re[6]: volatile у переменной класса
    От: MaximE Великобритания  
    Дата: 23.06.05 08:40
    Оценка: 7 (1)
    Здравствуйте, Alex Alexandrov, Вы писали:

    AA>Здравствуйте, Mr. None, Вы писали:


    MN>>А если в подробностях ? Может статью на эту тему, а то ощущается некая нехватка собранной и структурирванной информации на эту тему, причём на русском языке (помните главную идеологию RSDN — обширный портал для руско-говорящих программистов )


    AA>Я подумаю над этим. Макс, порецензируешь, если что?


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

    []

    AA>Но самый надежный способ — все-таки примитивы синхронизации и атомарные Interlocked* функции. Как жаль, правда, что в Posix нет аналогов Interlocked*. Понимаю, что дань независимости от конкретных возможностей процессоров, но все равно жаль...


    На практике, под POSIX пишут на gcc, или компиляторе, совместимым с gcc (Intel). Поэтому IMO безопасно полагаться, что присутствуют ф-ции libstdc++ __gnu_cxx::__exchange_and_add и __gnu_cxx::__atomic_add.
    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 Великобритания  
    Дата: 18.01.05 12:38
    Оценка: 6 (1)
    What wrote:

    ... Другой пример — паттерн double-checked locking, при реализации которого, кстати, может понадобиться volatile.

    [q]
    http://groups-beta.google.com/group/comp.lang.c++.moderated/browse_frm/thread/811a3ae4eea2d481/

    The problem exists, because the C++ standard allows reordering of C++ statements,
    as long as the observable behaviour stays the same — with the bad side
    effect that the "observable behavior" in C++ is not multi-threading
    aware and this finally leads to Scott's conclusion: "There is no
    portable way to implement DCLP in C++".

    [/c]

    --
    Maxim Yegorushkin
    Posted via RSDN NNTP Server 1.9
    Re[9]: читаем про volatile
    От: MaximE Великобритания  
    Дата: 17.01.05 20:15
    Оценка: 4 (1)
    Seriously Serious wrote:

    > ME>Александреску был публично выпорон

    >
    > Хочется увидеть аргументы против такого использования volatile

    Ok, как единственный в этой ветке человек, умеющий пользоваться google groups и щелкающий по ссылкам данным здесь же , даю тебе ссылку:

    http://groups-beta.google.com/group/comp.programming.threads/msg/21878c22d7775997

    --
    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[8]: volatile у переменной класса
    От: MaximE Великобритания  
    Дата: 18.01.05 20:06
    Оценка: 3 (1)
    emusic wrote:

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

    >
    > ME>Ok, ты работаешь над проектом. Менеджер спрашивает тебя, готов ли ты поставить свою зарплату, что твой многопоточный кусок кода, в котором ты не используешь ф-ций синхронизации, а полагаешься на "fuzzy" семантику volatile, заработает на не Intel SMP системе?
    >
    > А ты свою зарплату за то, что код, использующий функции синхронизации, но не использующий volatile, заработает везде, поставишь? Только хорошо подумай перед тем, как согласиться

    Код который написал я — да.

    > Макс, ты тут ругал человека, что он не читает тред — а ты сам его разве читаешь? Тебе в который раз повторяют, что для гарантированной работы кода в общем случае обязательны и функции синхронизации, и volatile. Но тебе, похоже, комфортнее делать вид, будто все, как один, сторонники volatile предлагают использовать его вместо функций синхронизации


    Позволь тебя спросить: что ты думаешь про постинг Александра Терехова?

    Тебе не надоело упираться рогом в стену?

    Ты все еще надеешься увидеть мою реакцию на твой эмоциональный шантаж?

    --
    Maxim Yegorushkin
    Posted via RSDN NNTP Server 1.9
    Re[3]: volatile у переменной класса
    От: MaximE Великобритания  
    Дата: 09.01.05 21:47
    Оценка: 2 (1)
    Dr.Gigabit wrote:

    []

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


    http://rsdn.ru/forum/?mid=922675
    Автор: MaximE
    Дата: 29.11.04


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

    []

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


    Весь мир давно заездил эту тему до дыр, только до rsdn прогрессивная мысль никак не доберется (.

    --
    Maxim Yegorushkin
    Posted via RSDN NNTP Server 1.9
    Re[3]: [2]: : volatile: а можно примеры?
    От: eao197 Беларусь http://eao197.blogspot.com
    Дата: 17.01.05 10:48
    Оценка: 1 (1)
    Максим, я разделяю вашу точку зрения.

    Но мне интересно, когда уважаемые emusic, Шахтер, c-smile (извините, если не всех перечислил), отстаивали противоположное мнение, они имели в виду конкретные примеры из собственного опыта или из литературы, или это их интерпритация стардартов и спецификаций? Если примеры есть, то мне было бы очень интересно про них узнать, чтобы не повторять чужих ошибок.

    Предложение: давайте не превращать эту ветвь в очередное выяснение истины. Если есть примеры -- приводите, пожалуйста. Если нет, то будем считать это доказательством правильности позиции Максима


    SObjectizer: <микро>Агентно-ориентированное программирование на C++.
    Re[6]: [2]: : volatile: а можно примеры?
    От: Odi$$ey Россия http://malgarr.blogspot.com/
    Дата: 18.01.05 05:23
    Оценка: 1 (1)
    Здравствуйте, MaximE, Вы писали:

    ME>Мой поинт был в том (если этого до сих пор непонятно уважаемому Шахтеру), что какой бы семантикой не обладал volatile, ее просто не достаточно для multithreading, и поэтому volatile бесполезен для multithreading.


    не вдаваясь в технические подробности, из "недостаточно" никак не может следовать "и поэтому ... бесполезен"
    Re[2]: Реальный пример использования volatile
    От: What Беларусь  
    Дата: 18.01.05 11:28
    Оценка: 1 (1)
    Здравствуйте, eao197, Вы писали:

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


    E>Но ведь здесь не используются примитивы синхронизации! С моей точки зрения, это как раз опасная практика -- изменять значение в одном потоке без блокирования чтения из другого потока.


    А зачем здесь синхронизация? Один поток пишет значение переменной, другой читает. Главное, чтобы значение было записано атомарно. Это в данном случае для x86 гарантируется.
    С другой стороны, а если бы рабочих потоков было, скажем, 4 вместо 1. И все читали бы одну и ту же переменную. Тогда использование синхронизации могло бы привести к ненужным потерям производительности.

    E>Если бы вы использовали синхронизацию доступа к go, то volatile, наверняка, не потребовался бы.

    Наверняка, да, не потребовался бы.
    ... << RSDN@Home 1.1.4 beta 3 rev. 185>>
    Re[5]: volatile у переменной класса
    От: emusic Франция https://software.muzychenko.net/ru
    Дата: 10.01.05 18:43
    Оценка: -1
    Здравствуйте, MaximE, Вы писали:

    ME>Использование любого примитива синхронизации в POSIX и win32 является вызовом ф-ции. Вызов ф-ции — sequence point. Если у тебя уже есть sequence points вокруг защищаемых данных, зачем тогда volatile?


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

    Например, в Windows MME в описателе звукового буфера есть флажок WHDR_DONE, означающий, что драйвер завершил обработку буфера. Можно, конечно, заказать специфическое уведомление, но можно и просто опрашивать этот флажок время от времени. Что запретит компилятору перечитывать его из памяти, если весь описатель не будет объявлен с volatile?

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


    ME>Это так только по случайному стечению обстоятельств на IA32.


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

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


    А зачем? Назначение volatile — влиять именно на код. Соответственно, процессор своими средствами обеспечивает определенность вычислений.

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


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

    >> ME> После sequence points, компилятор обязан перечитывать значения переменных из памяти, неважно, volatile ли, const ли, или это переменная без cv-квалификатора

    >>
    >> С чего бы он вдруг стал обязан? Компилятор обязан лишь обеспечить последовательное выполнение заданных действий в рамках одного потока исполнения. Для взаимодействия с "внешними" процессами и существует volatile.

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


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

    >> Простейший пример:

    >>
    >>
    >> void f (int &a, int &b) {
    >>   if (!a) {
    >>     b = a;
    >>   }
    >> }
    >>

    >>
    >> При включенной оптимизации многие компиляторы (например, VC++ 6.0) сгенерируют только один опрос переменной a — в проверке условия. Для присваивания будет сгенерирован явный нуль.

    ME>Здесь именно простейший пример: нет вызовов ф-ций, компилятор видит весь контекст и плевал на sequence points. Добавим вызов ф-ции.


    А давай вместо вызова функции добавим модификацию объекта — например, введем переменную c и сделаем ей инкремент:

      int c = b;
    
      if (!a) {
    
        c++;
    
        b = a;
    
      }
    
      return c;


    Модификация объекта, согласно стандарту, есть sequence point. А по соглашениям MS любой оператор также является SP, и условие в if является ею же. Однако это не мешает компилятору по-прежнему использовать константу-нуль.

    Я вообще не понимаю, почему ты относишь значение объекта к side effects.

    ME>Мой point: volatile бесполезен (и даже вреден) для multithreading, барьеры нужны по-любому.


    Где в C++ барьеры? Их там нет — они реализуются средствами платформы. Наличие барьеров без volatile не гарантирует правильной работы. Наличие volatile без барьеров — тоже не гарантирует. volatile обеспечивает поддержку со стороны языка, барьер — со стороны аппаратуры. Зачем, по-твоему, вообще существует volatile? Именно для урезания вольностей оптимизатора в отношении состояния объекта.
    ... << RSDN@Home 1.1.4 beta 3 rev. 185>>
    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[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[7]: читаем про volatile
    От: MaximE Великобритания  
    Дата: 11.01.05 19:32
    Оценка: :)
    Здравствуйте, Seriously Serious, Вы писали:

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


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

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

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

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

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

    volatile нужно для того чтобы компилятор не кешировал значение переменной. Т.Е. Обычно компилятор оптимизирует использование переменных путем помещения их значения в регистры процессора. Если установить у переменной идентификатор volatile, то компилятор создаст такой код при котором при доступе к переменной её значение всегда будет читаться из памяти, и это значение не будет помещятся в регистры процесора.
    Данная техника полезна в многопоточных приложениях, в том случае когда один поток записывает значение в переменную, а другой читает. Если в этом случае у переменной не будет модификатора volatile то может получится так, что компилятор поместит значения переменной в двух потоках в регистры процессора, и тогда изменение значение переменной в одном потоке, не повлияет на изменение переменной в другом потоке.
    Re[12]: volatile у переменной класса
    От: MaximE Великобритания  
    Дата: 15.01.05 12:27
    Оценка: -1
    Шахтер wrote:

    > ME>Я скомпилировал следующий код на VC71 и Intel 8 с максимальными настройками оптимизации, с LTCG/IPO и без. Во всех четырех случаях при чтении переменная не кэшировалась, неважно, volatile ли была переменная или нет.

    >
    > Ты не совсем прав в данном случае. Нет никаких гарантий, что подобное поведение сохраниться в будующем. В этом примере компилятор не смог оценить побочные эффекты от вызова Sleep, поэтому и перечитал переменную из памяти. А вот теперь уберем Sleep. И получим звездец.

    Ты хочешь сказать, что добавим volatile — и все ok? Действительно, это может заставить компилятор прочитать значение из памяти, а может и нет, так как семантика volatile — implementation defined.

    Чтение из памяти на текущих процессорах Intel гарантировано прочитает актуальное значение, даже если память была изменена в кэше другого процессора, т.к. Intel для текущих процессоров применяет cache snooping.

    When operating in an MP system, IA-32 processors (beginning with the Intel486 processor) have the ability to snoop other processor’s accesses to system memory and to their internal caches. They use this snooping ability to keep their internal caches consistent both with system memory and with the caches in other processors on the bus. For example, in the Pentium and P6 family processors, if through snooping one processor detects that another processor intends to write to a memory location that it currently has cached in shared state, the snooping processor will invalidate its cache line forcing it to perform a cache line fill the next time it accesses the same memory location.


    > И в будующем ситуация может стать аналогичной и с вызовом Sleep. Дело в том, что существует предложение о введении спецификатора для функций без побочных эффектов (pure). Если это будет реализовано и функция Sleep будет помечена как pure, то и её вызов не будет рассматриваться компилятором как могущий изменить переменную a, что приведёт к нежелательной оптимизации.


    В будущем для Intel и в настоящем для многих других процессоров, volatile точно не поможет, так как на Intel он опирается на две processor dependent фичи: на memory ordering и когерентность кешей (cache snooping выше).

    7.2.1. Memory Ordering in the Pentium® and Intel486™ Processors

    The Pentium and Intel486 processors follow the processor-ordered memory model; however, they operate as strongly-ordered processors under most circumstances. Reads and writes always appear in programmed order at the system bus—except for the following situation where processor ordering is exhibited. Read misses are permitted to go ahead of buffered writes on the system bus when all the buffered writes are cache hits and, therefore, are not directed to the same address being accessed by the read miss.

    In the case of I/O operations, both reads and writes always appear in programmed order.

    Software intended to operate correctly in processor-ordered processors (such as the Pentium 4, Intel Xeon, and P6 family processors) should not depend on the relatively strong ordering of the Pentium or Intel486 processors. Instead, it should insure that accesses to shared variables that are intended to control concurrent execution among processors are explicitly required to obey program ordering through the use of appropriate locking or serializing operations (see Section 7.2.4., “Strengthening or Weakening the Memory Ordering Model”).

    ...

    7.2.4. Strengthening or Weakening the Memory Ordering Model
    ...
    It is recommended that software written to run on Pentium 4, Intel Xeon, and P6 family processors assume the processor-ordering model or a weaker memory-ordering model. The Pentium 4,
    Intel Xeon, and P6 family processors do not implement a strong memory-ordering model, except when using the UC memory type. Despite the fact that Pentium 4, Intel Xeon, and P6 family processors support processor ordering, Intel does not guarantee that future processors will support this model. To make software portable to future processors, it is recommended that operating systems provide critical region and resource control constructs and API’s (application
    program interfaces) based on I/O, locking, and/or serializing instructions be used to synchronize access to shared areas of memory in multiple-processor systems. Also, software should not depend on processor ordering in situations where the system hardware does not support this memory-ordering model.




    Так что volatile не является ни необходимым, ни достаточным для multithreading. Если малтитредовой проге необходим volatile чтобы корректно работать, такая программа непортабельна.

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

    ME>Я про это и пишу:

    ME>

    ME>Так что volatile не является ни необходимым, ни достаточным для multithreading. Если малтитредовой проге необходим volatile чтобы корректно работать, такая программа непортабельна.


    Обосновать это свое утверждение чем-либо, кроме собственной смутной интуиции, можешь? Я тебе привел пример программы, которая без volatile корректно работать не будет. Найди в этом примере ошибку, либо приведи доказательство того, что любая многопоточная программа обязана корректно работать без volatile. Пока бОльшую часть приведенных тебе аргументов ты тихо опускаешь, повторяя в ответ одни и те же измышления.
    ... << RSDN@Home 1.1.4 beta 3 rev. 185>>
    Re[15]: volatile у переменной класса
    От: Шахтер Интернет  
    Дата: 16.01.05 00:59
    Оценка: :)
    Здравствуйте, MaximE, Вы писали:

    ME>emusic wrote:


    ME>[]


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


    ME>Весь мир давно заездил эту тему до дыр, только до rsdn прогрессивная мысль никак не доберется (.


    ME>--

    ME>Maxim Yegorushkin

    В данном случае ты очень крупно заблуждаешься. Насчет заезженной темы -- ключевое слово volatile появилось очень давно и имеет вполне определённую семантику использования, которая поддерживается C/C++ компиляторами. Если кто-то плохо знаком с вопросом и фантазирует на тему в том или другом форуме, то это личная беда этих людей. Вместо того, чтобы упираться, изучи лучше листинги, которвые я тебе привел -- они очень красноречивы.
    ... << RSDN@Home 1.1.0 stable >>
    В XXI век с CCore.
    Копай Нео, копай -- летать научишься. © Matrix. Парадоксы
    Re[15]: volatile у переменной класса
    От: emusic Франция https://software.muzychenko.net/ru
    Дата: 16.01.05 04:57
    Оценка: -1
    Здравствуйте, MaximE, Вы писали:

    ME>emusic wrote:


    >> Указание ключа /Oa сообщает компилятору, что в программе подобные совмещения исключены.


    ME>... но на самом деле они у тебя в проге есть и ты полагаешься на результат этого альясинга. Ты сообщил компилятору неверную информацию — all bets are off.


    Чтоб ты не измыслил очередной ерунды — приведу перечень условий отсутствия aliasing'а из MSDN. Будь любезен, укажи, какие места моего примера какие из этих пунктов нарушают:

    If you use /Oa or /Ow, you must follow these rules. The following rules apply for any variable not declared as volatile:

    No pointer can reference a variable that is used directly (a variable is referenced if it is on either side of an assignment or if a function uses it in an argument).
    No variable can be used directly if a pointer to the variable is being used.
    No variable can be used directly if its address is taken within a function.
    No pointer can be used to access a memory location if another pointer modifies the same memory location.


    Разумеется, ты будешь ссылаться на четвертый пункт, ибо переменной в "чистом" виде в программе может и не быть Однако с чего ты взял, что в программе одновременно будет существовать два указателя на одну и ту же область? Напомню, ты сам дважды подчеркивал, что многопоточность в модели C++ отсутствует. И "в пространстве" (в каждом отдельном потоке) может существовать не более одного указателя на каждую область памяти. Это и есть отсутствие aliasing'а, о чем сообщается компилятору.

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

    ME>Весь мир давно заездил эту тему до дыр, только до rsdn прогрессивная мысль никак не доберется (.


    Слушай, а может, у тебя с английским плохо? В этих дискуссиях никто америки не открыл, и большинство компетентных мнений сходится, конечно же, к тому, что ни volatile, ни memory barriers сами по себе проблемы не решают, и в общем случае решают ее лишь в совокупности. А ты с самого начала уперся в простейшие частные случаи вроде InterlockedXXX, и необязательность volatile для таких переменных смело распространил на все остальное, опираясь на наиболее одиозные утверждения в приведенном списке ссылок Конечно, если читать из этого списка только то, где высказывается близкая тебе точка зрения, в подобное заблуждение впасть нетрудно
    ... << RSDN@Home 1.1.4 beta 3 rev. 185>>
    Re[2]: : volatile: а можно примеры?
    От: MaximE Великобритания  
    Дата: 17.01.05 10:02
    Оценка: +1
    eao197 wrote:

    > В связи с этим у меня вопрос: можно ли услышать/увидеть реальные примеры того, как в многопоточных приложениях обнаруживались проблемы из-за того, что не использовалось volatile? Именно реальные, хорошо бы с примерами, хотя бы псевдокода. И не драйверов или софта для работы с железом, а "прикладного" кода.


    С использованием средств синхронизации никаких проблем без volatile нет и быть не должно.

    > Просто у меня сложилось такое мнение, что сейчас что с volatile, что без, если используешь штатные средства синхронизации (будь то WinAPI или POSIX), то можно быть спокойным. Более того, разработчики компиляторов не могут не учитывать того факта, что в мире немало программистов (я из их числа), которые не озаботились применением volatile в многопоточном приложении. И если выйдет новая версия компилятора, для которого применение volatile критически важно, то все эти программисты столкнутся с огромным объемом неработоспособного кода. Поэтому можно ожидать, что и в новых компиляторах многопоточные приложения без volatile останутся работоспособными. Но это мое впечатление.


    Маловероятно, что кто-то выпустит такой компилятор — его непросто будет продавать, да и tech. support calls разработчикам компилятора не нужны.

    --
    Maxim Yegorushkin
    Posted via RSDN NNTP Server 1.9
    Re[8]: читаем про volatile
    От: Seriously Serious  
    Дата: 17.01.05 18:58
    Оценка: :)
    Здравствуйте, MaximE, Вы писали:

    ME>Александреску был публично выпорон


    Хочется увидеть аргументы против такого использования volatile
    Re[6]: volatile у переменной класса
    От: Tom Россия http://www.RSDN.ru
    Дата: 18.01.05 09:43
    Оценка: +1
    ME>Т.е. ты взял и не читая ляпнул?
    Не горячись

    ME>http://www.rsdn.ru/forum/?mid=989456
    Автор: MaximE
    Дата: 16.01.05

    ME>http://www.rsdn.ru/forum/?mid=988910
    Автор: MaximE
    Дата: 15.01.05

    ME>http://www.rsdn.ru/forum/?mid=991653
    Автор: MaximE
    Дата: 17.01.05


    Знавчицца так: Берёшь простенькую программу с обьявленной глобальной volatile и нет переменной. Компилируешь в релизе разными компиляторами. Я проверял на: VC6, VC7.1, gcc 2.95, gcc 3.2, Sun One Studio 5. И смотришь разницу

    Ещё раз говорю, что переменная, использующаяся в разных потоках, кроме того, что должна быть защищена приметивами синзхронизации обязана быть volatile.
    Народная мудрось
    всем все никому ничего(с).
    Re[10]: volatile у переменной класса
    От: Tom Россия http://www.RSDN.ru
    Дата: 18.01.05 10:46
    Оценка: :)
    ME>Это здесь уже обсудили. Он ни достаточен, ни необходим. Вся информация тебе доступна, читай.
    То, что он нидостаточен — это естественно, Но он необходим. Советую не ляпать на клавиатуре, а попробовать самому
    Народная мудрось
    всем все никому ничего(с).
    Re[13]: volatile у переменной класса
    От: MaximE Великобритания  
    Дата: 18.01.05 12:17
    Оценка: +1
    Tom wrote:

    > ME>Приведи конкретный пример.

    >
    > Сырец

    []

    > Вот и представь, что Thread, испольняется несколькими потоками... Выходит, что потоки узнают о изменениях переменной, только тогда, когда компилятор соизволит слить её в память, а он может этого неделать оочень долго... Почувствуйте разницу


    Этот код — некорректный многопоточный код, так как он не применяет синхронизацию для доступа к переменной.

    Это уже обсуждалось в ветке.

    --
    Maxim Yegorushkin
    Posted via RSDN NNTP Server 1.9
    Re[14]: volatile у переменной класса
    От: Tom Россия http://www.RSDN.ru
    Дата: 18.01.05 12:51
    Оценка: :)
    ME>Этот код — некорректный многопоточный код, так как он не применяет синхронизацию для доступа к переменной.

    А ты думаешь компилятор перестанет оптимизировать, если появиться синхронизация?
    Народная мудрось
    всем все никому ничего(с).
    Re[17]: volatile у переменной класса
    От: emusic Франция https://software.muzychenko.net/ru
    Дата: 18.01.05 19:16
    Оценка: +1
    Здравствуйте, achp, Вы писали:

    A>Хм... Если есть барьер, то зачем volatile?


    Бааалин. Глухой телефон Кто обещал, что барьер можно специфицировать на конкретный объект? Если на каждый объект сделать функцию, которая обеспечивает сливание его в память на одном процессоре и всасывание в другом — разумеется, компилятор после выполнения этой функции перечитает любую часть объекта из памяти, ибо в функцию будет передаваться неконстантная ссылка

    А если барьер неспецифичный, вроде KeMemoryBarrier в виндовом ядре? Как объяснить компилятору, что после вызова некоторой функции без аргументов последнее известное значение объекта уже нельзя считать валидным? Разумеется, если не применять глубокой оптимизации — компилятор будет осторожничать и перечитывать после каждого вызова неизвестной ему функции. Указание volatile для разделяемых объектов позволит ему максимально оптимизировать остальные объекты. Если охота еще и оптимизации разделяемых объектов — значит, нужны специфичные барьерные примитивы на каждый разделяемый объект.
    ... << RSDN@Home 1.1.4 beta 3 rev. 185>>
    Re[17]: volatile у переменной класса
    От: achp  
    Дата: 18.01.05 19:50
    Оценка: +1
    Здравствуйте, emusic, Вы писали:

    E>Это верно только для нелокальных переменных. Я уже приводил код с указателями. В каждом потоке в каждый момент времени существует только один указатель на объект, по которому может производиться доступ. Следовательно, допустимо применить оптимизацию работы с указателями, задав компилятору режим No Aliasing.


    Ну правильно, это же прямой обман компилятора. И вообще это чрезмерно агрессивная оптимизация, в общем случае недопустимая.
    Я кончил, джентльмены, мне остается только поблагодарить вас за внимание.
    Необходимость/желательность volatile
    От: emusic Франция https://software.muzychenko.net/ru
    Дата: 19.01.05 12:30
    Оценка: +1
    Здравствуйте, MaximE, Вы писали:

    ME>Компилятор должен поддерживать многопоточность — это раз.


    Из чего следует, что компилятор должен ее поддерживать своими силами? Компилятор предоставляет средства для отражения многопоточного характера кода. Пользоваться этими средствами или нет — выбор программиста.

    ME>Семантика volatile — implementation defined — это два.


    Опять-таки, из чего следует? Семантика volatile как раз установлена стандартом, и выражается в сохранении последовательности чтения/записи таких данных. То есть — везде, где конструкцией языка подразумевается использование значения — оно читается, где подразумевается изменение — оно записывается. А уж каким конкретно образом сие будет реализовано — это, как и все остальное, implementation-defined.

    ME>Никакой стандарт не гарантирует, что volatile вставит load инструкцию


    Это уже дело компилятора — вставлять ли инструкцию, и какую именно. Стандарт предписывает сохранить "порядок чтения/записи".

    К слову, не следует с таким пиететом относиться к стандарту. Это не настолько самодостаточный документ, чтобы объяснять все возможные нюансы. Например, он использует понятие "sequence of reads and writes to volatile data", но нигде не объясняет, где и отчего возникают эти "reads" и "writes", оперируя в дальнейшем высокоуровневыми понятиями.

    ME>Во-первых, load инструкция, в-общем, не гарантирует загрузку актуального значения из памяти без использование барьеров памяти.


    Опять двадцать пять. Ты снова начинаешь доказывать, что одного volatile недостаточно, хотя ни один из участников треда в этом с тобой не спорил. С тобой спорят только в части утверждения "volatile бесполезен и даже вреден".

    ME>Есть тип, который гарантирует атомарность load и store на конкретной платформы для переменной этого типа — это sig_atomic_t. Только, почему-то, нет типа thread_atomic_t.


    Может быть, потому, что в стандарте нет понятия "thread"?

    ME>И сейчас утверждаю, что volatile бесполезен и вреден для multithreading.

    ME>Одно из применений multithreading — получить максимальное быстродействие, задействовав все процессоры системы.

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

    ME> С другой стороны, volatile variables связывают руки оптимизатору. Звучит глупо: хочешь добиться максимального быстродействия, но запрещаешь оптимизацию.


    Если бы ты изначально сформулировал свою мысль, как "volatile вреден для эффективного multithreading" — с тобой опять-таки никто не спорил бы. Я уже говорил о систематическом и необоснованном расширении тобой частных утверждений. Может, тебе стоит обращать больше внимания на соответствие того, что ты пишешь, тому, что при этом подразумеваешь? Телепаты, однако, в отпуску.

    ME>Компилятор, который бы требовал применение volatile к thread shared variables для конкретной платформы по этой причине попросту бы там не продавался.


    Да потому, что на данном этапе проще не упираться в столь тонкую оптимизацию в стандартных ее режимах, вот и все.

    Для максимального быстродействия многопоточки volatile действительно вреден. А вот для максимальной надежности ее же он может быть исключительно полезен, ибо позволяет привязывать расстановку барьеров не к коду, а к данным. Если в многопоточном процессе типа "писатель-читатели" модификация объекта происходит редко, а использование — часто, то достаточно тяжело следить за расстановкой отдельных барьеров при каждом использовании. А volatile позволяет компилятору, которые знает про свою платформу и про барьеры, это дело соответствующим образом обеспечить.

    ME>Приведи пункт стандарта или соответсвующий текст из reference manual к какой либо threading model


    В другом ответе я привел цитату из MSDN (статья 120926). Но тебе она, конечно же, покажется неубедительной.

    ME>Эта оговорка, а лучше сказать ошибка, сидит в секции C/C++ Language Reference с незапамятных времен. Как умеют люди из mictrosoft трактовать C++ стандарт и писать код на C++ мы все тут знаем.


    Насчет того, что не стоит превозносить C++ Standard, я уже писал. Это тоже отнюдь не тот документ, на который нужно равняться в отношении ясности, прозрачности и непротиворечивости. MSDN выгребает хотя бы за счет объема и количества — порывшись в ней как следует, почти всегда можно найти правильный ответ (или, хотя бы, направление дальнейшего поиска). Где предлагаешь копаться, чтобы найти ответы на вопросы, не освещенные в стандарте C++?

    А про "трактовку стандарта людьми из microsoft" — она в основном базируется на ламерских наездах на реализацию for и подобных конструкций в компиляторах до 7.0. Почитал человек стандарт 98 года, поставил себе VC++ 5.0 или 6.0, обнаружил там несоответствия — и давай привычно поливать MS А сообразить, что все эти компиляторы выпущены до принятия стандарта, ума не хватает. Много ли претензий по несовместимости со стандартом к компиляторам седьмой версии?

    ME>Скачай Platform SDK, и найди в его документации упоминание о том, что thread shared variables должны быть volatile.


    А где ты в этой документации нашел упоминания о том, что любые обращения к разделяемым данным должны быть защищены определенными примитивами синхронизации? Таких утверждений там тоже нет, говорится лишь, что доступ "must be synchronized". А как его синхронизировать — дело программиста. В частности, описаны варианты исключительно с volatile и без единого примитива ОС.
    ... << RSDN@Home 1.1.4 beta 3 rev. 185>>
    Re[11]: [2]: : volatile: а можно примеры?
    От: achp  
    Дата: 20.01.05 10:34
    Оценка: +1
    Здравствуйте, Andrew S, Вы писали:

    AS>V2. Переменная объявлена не как volatile. Соотв, параметры InterlockedXxx без volatile (например, как это было в PSDK 2-х летней давности. Теперь это не так и вынуждает программистов использовать volatile для этих функций.


    С какой радости? Преобразования указателей от менее cv-квалифицированных к более cv-квалифицированным происходят неявно.
    Я кончил, джентльмены, мне остается только поблагодарить вас за внимание.
    Re[10]: [2]: : volatile: а можно примеры?
    От: MaximE Великобритания  
    Дата: 20.01.05 10:53
    Оценка: +1
    eao197 wrote:

    > ... Поэтому еще раз проясню свою позицию: я хочу увидеть реальные примеры (из реальных, а не тестовых примеров), когда использовались примитивы синхронизации, но приложение все равно работало не правильно до тех пор, пока не было использовано volatile. При этом меня не интересуют ни обработчики аппаратных прерываний, ни работа с железом через отображаемые в память порты ввода/вывода.

    >
    > Прошу не приводить примеров, когда компилятору специальными ключами явно указывали, что ни одна функция не имеет побочных эффектов. Применение такого ключа в многопоточной программе, ИМХО, является проявлением излишнего оптимизма программиста. Кроме того, такой пример я уже видел. Может есть что-то еще?

    Полностью согласен и тоже хочу увидеть пример.

    --
    Maxim Yegorushkin
    Posted via RSDN NNTP Server 1.9
    Re[4]: ужас
    От: MaximE Великобритания  
    Дата: 20.01.05 11:26
    Оценка: :)
    achp wrote:

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

    >
    > ME>Гарантируется. После вызова "непрозрачной" ф-ции компилятор будет перечитывать значения всех переменных из памяти. В противном случае даже single threaded код работать не будет.
    >
    > Ну, положим, не совсем всех. Если это локальная переменная, адрес которой нигде "налево" не "утекал", то её вполне можно заховать и в регистре.

    Он может утечь не явно.

    ("Непрозрачная") ф-ция может взять адрес возврата, по .pdb файлу определить, что это за вызывающая ф-ция, получить адрес ее фрейма и пробежаться по ее переменным и аргументам — no big deal.

    --
    Maxim Yegorushkin
    Posted via RSDN NNTP Server 1.9
    Re[11]: volatile
    От: emusic Франция https://software.muzychenko.net/ru
    Дата: 21.01.05 03:34
    Оценка: :)
    Здравствуйте, emusic, Вы писали:

    SS>>В таком случае, есть ли какое-нибудь полезное применение volatile на UDT? (в смысле, чтобы можно было только функции с volatile вызывать)


    Вроде тут уже многократно обсудили, в чем состоит полезность и вредность volatile для любого типа Что осталось непонятым?
    ... << RSDN@Home 1.1.4 beta 3 rev. 185>>
    Re[11]: [2]: : volatile: а можно примеры?
    От: eao197 Беларусь http://eao197.blogspot.com
    Дата: 21.01.05 08:32
    Оценка: +1
    Здравствуйте, c-smile, Вы писали:

    CS>На моей задаче aliasing оптимизация дает 16% прирост производительности. Поэтому без этой оптимизации я даже и не компилирую.

    CS>http://terrainformatica.com/htmlayout

    Это веский аргумент. Но применяя такую оптимизацию нужно быть готовым к тому, что даже однопоточное приложение без volatile работать не будет. Например:
    tm * parsed = localtime( time( 0 ) );
    int * sec = &parsed->tm_sec;
    while( <something> )
        {
            <do something>
            localtime( time( 0 ) );
            if( *sec ) ...
        }

    Что удержит компилятор от того, чтобы не закешировать в регистре значение по указателю sec? /чтобы не было возражений по поводу корректности сохранения в sec указателя на возвращаемое localtime значение хочу сразу сказать, что вместо localtime можно было бы использовать любую другую функцию для которой это можно считать корректным/

    В качестве оффтопика хочу заметить, что этот аргумент становится действительно веским при условии, что алгоритмически увеличить быстродействие не получается. На днях я смог достичь 2-х кратного увеличения производительности одного из критически важных участков кода просто заменив использование двух разных буферов одним большим буфером, в по которому, не пересекаясь двигаются два независимых указателя. И режим оптимизации (простой /O2) не изменялся. Пожалуйста, c-smile, не принимайте эти слова, как сомнения в вашей компетенции. Это просто ремарка, о том, что иногда увеличения производительности можно добиться сменой алгоритма, а не параметра оптимизации.

    Спасибо за ваш пример. Но как и пример What-а
    Автор: What
    Дата: 18.01.05
    его можно считать очень платформенно-зависимым. Ведь вы из-за соображений производительности отказались от использования штатных примитивов синхронизации (критические секции или mutex-а), а сделали свои. И естественно, были вынуждены использовать volatile, поскольку в отсутствии обращений к внешним функциям ничего не запрещало компилятору "оптимизировать" работу с переменными.

    Но пример действительно интересный, если столкнусь с непреодолимыми потерями производительности, то попробую сделать что-нибудь похожее. С volatile, разумеется
    ... << RSDN@Home 1.1.4 beta 3 rev. 185>>


    SObjectizer: <микро>Агентно-ориентированное программирование на C++.
    Re[2]: volatile у переменной класса
    От: gwg-605 Россия  
    Дата: 21.01.05 17:33
    Оценка: -1
    Здравствуйте, MaximE, Вы писали:

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

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

    ME>Рихтер ошибался.

    Без коментариев

    ME>volatile не имеет никакого отношения к multithreading, поэтому его применение в этой ситуации не только бесполезно, но может быть и вредно, так как с volatile компилятор не сможет соптимизировтать доступ к этой переменной. Но если один из потоков изменяет переменную, синхронизация при помощи мютексов обязательна.

    volatile имеет отношение к multithreading, хотя со стороны может показаться что и нет, да и ноги начали расти из другого места. На самом деле модификатор запрещает компилятору оптимизировать доступ к данной переменной.
    Синхронизация с помощью Mutex-ов достаточно накладна, и главное не всегда нужна. Простейший пример переменная-флаг.

    Валерий.
    ЗЫ. Это объяснение почему поставил минус.
    ... << RSDN@Home 1.1.4 beta 3 rev. 185>>
    Re[6]: : volatile: а можно примеры?
    От: Alexey_ch Швейцария  
    Дата: 21.06.05 12:10
    Оценка: +1
    Здравствуйте, <Aiiiei>, Вы писали:

    Aii>Не понял. А почему он будет работать?

    Aii>Из моего опыта он работать не будет если включена оптимизация.

    Если LOCK и UNLOCK макросы для системных функций синхронизации, то VC 7.1 всегда генерит корректных код. Он допускает, что внешняя функция может изменить глобальную переменную.

    А без функций в циклах оно работает неверно. Может быть VC 6.0 в данной ситуации делает вечный цикл, я не знаю .

    Вот мой тестовый пример.

    // stdafx.h : include file for standard system include files,
    // or project specific include files that are used frequently, but
    // are changed infrequently
    //
    
    #pragma once
    
    
    #include <iostream>
    #include <tchar.h>
    #include <process.h>
    #include <windows.h>
    #include <string>



    // sync_err_without_volatile.cpp : Defines the entry point for the console application.
    //
    
    #include "stdafx.h"
    
    int  /*volatile*/ g_counter  = 0;
    bool /*volatile*/ g_stopFlag = false;
    
    CRITICAL_SECTION g_cs;
    
    void __inline sub1();
    void __inline sub2();
    
    unsigned __stdcall Thread1(void* param)
    {
      for (auto int i = 0; i < 100000000; i++)
      {
        g_counter++;
        //sub1();
      }
    
      EnterCriticalSection(&g_cs);
      g_stopFlag = true;
      fprintf(stdout, "\nThread1 is ended: g_counter = %u", g_counter);
      LeaveCriticalSection(&g_cs);
    
      return 0;
    }
    
    unsigned __stdcall Thread2(void* param)
    {
      for (auto int i = 0; (i < 1000000000) && (!g_stopFlag); i++)
      {
        g_counter++;
        //sub2();
      }
    
      EnterCriticalSection(&g_cs);
      fprintf(stdout, "\nThread2 is ended: g_counter = %u", g_counter);
      LeaveCriticalSection(&g_cs);
    
      return 0;
    }
    
    void __inline sub1 (void)
    {
      EnterCriticalSection(&g_cs);
      g_counter++;
      LeaveCriticalSection(&g_cs);
    }
    
    void __inline sub2 (void)
    {
      EnterCriticalSection(&g_cs);
      g_counter++;
      LeaveCriticalSection(&g_cs);
    }
    
    
    int _tmain(int argc, _TCHAR* argv[])
    {
      InitializeCriticalSection(&g_cs);
    
      unsigned tr_id1, tr_id2;
    
      HANDLE h1 = (HANDLE) _beginthreadex(NULL, 0, &Thread1, NULL, CREATE_SUSPENDED, &tr_id1);
      HANDLE h2 = (HANDLE) _beginthreadex(NULL, 0, &Thread2, NULL, CREATE_SUSPENDED, &tr_id2);
    
      ResumeThread(h2);
      ResumeThread(h1);
      
      getchar();
      DeleteCriticalSection(&g_cs);
      return 0;
    }
    ... << RSDN@Home 1.1.4 beta 7 rev. 0>>
    volatile у переменной класса
    От: Vet  
    Дата: 09.01.05 11:26
    Оценка:
    В объекте класса есть переменная, которая используется двумя потоками.
    Один из потоков иногда меняет ее значение.
    Есть ли необходимость в этом случае делать переменную как volatile.
    И зависит ли ответ от того, сздан ли объект класса на стеке или в динамической памяти.

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

    11.01.05 07:45: Перенесено модератором из 'C/C++. Прикладные вопросы' — Павел Кузнецов
    Re[2]: volatile у переменной класса
    От: Dr.Gigabit  
    Дата: 09.01.05 21:16
    Оценка:
    Здравствуйте, MaximE, Вы писали:

    ME>Vet wrote:


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

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

    ME>Рихтер ошибался.


    ME>volatile не имеет никакого отношения к multithreading, поэтому его применение в этой ситуации не только бесполезно, но может быть и вредно, так как с volatile компилятор не сможет соптимизировтать доступ к этой переменной. Но если один из потоков изменяет переменную, синхронизация при помощи мютексов обязательна.


    Не могли бы вы более подробно пояснить, зачем тогда вообще использовать volatile? Всегда думал, что volatile обозначает, что данные могут изменяться без ведома компилятора(в том числе и с помощью многопоточности). Т.е. компилятор не должен делать никахих предположений о значении переменной, в частности, в целях оптимизации.
    ... << RSDN@Home 1.1.4 @@subversion >>
    Re[2]: volatile у переменной класса
    От: MaximE Великобритания  
    Дата: 10.01.05 08:14
    Оценка:
    c-smile wrote:

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

    >
    > Vet>В объекте класса есть переменная, которая используется двумя потоками.
    > Vet>Один из потоков иногда меняет ее значение.
    > Vet>Есть ли необходимость в этом случае делать переменную как volatile.
    > Vet>И зависит ли ответ от того, сздан ли объект класса на стеке или в динамической памяти.
    >
    > Vet>Вопрос вызван тем, что у Рихтера прочитал, что если глобальная переменная используется
    > Vet>разными потоками, то она обязана быть volatile. Вот меня и рабирают сомнения нужно ли
    > Vet>тоже самое делать для переменных(членов) класса.
    >
    > Да, обязательно, иначе оптимизатор тебе такого наворотит — не обрадуешься.
    >

    > The volatile keyword is a type qualifier used to declare that an object can be modified in the program by something other than statements, such as the operating system, the hardware, or a concurrently executing thread.


    Это не так. Кусок не из стандарта, а наверное, из MSDN. Почитайте про sequence points.

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

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

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

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

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

    --
    Maxim Yegorushkin
    Posted via RSDN NNTP Server 1.9
    Re[4]: volatile у переменной класса
    От: MaximE Великобритания  
    Дата: 10.01.05 17:06
    Оценка:
    emusic wrote:

    >>> The volatile keyword is a type qualifier used to declare that an object can be modified in the program by something other than statements, such as the operating system, the hardware, or a concurrently executing thread.

    >>> [/q]
    >
    > ME>Это не так. Кусок не из стандарта, а наверное, из MSDN. Почитайте про sequence points.
    >
    > Sequence points — это вообще из другой оперы. Sequence point — место, где заканчиваются побочные эффекты, и не более того. Причем относится это исключительно к имеющему место "потоку выполнения", и к параллельным потокам отношения не имеет.

    Именно так. Стандарт вообще не упоминает никаких потоков кроме единственного control flow и еще упоминают обработчики сигналов, для которых собственно и был придуман volatile.

    И это проблема стандарта, над которой уже работают умы. http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1680.pdf

    > А вот при наличии volatile при каждом обращении к такому объекту формируется sequence point.


    Именно так.

    > Прохождение sequence point отнюдь не гарантирует, что состояния всех объектов в этой точке будут непременно отражены в памяти — это гарантируется только для volatile-объектов.


    Я этого и не утверждал, как раз я утверждаю обратное.

    Все что я утверждал, что volatile бесполезен, потому, что он не сделает не потокобезопасный код потокобезопасным. Потокобезопасность достигается использованием соответствующих примитивов синхронизации. Использование любого примитива синхронизации в POSIX и win32 является вызовом ф-ции. Вызов ф-ции — sequence point. Если у тебя уже есть sequence points вокруг защищаемых данных, зачем тогда volatile?

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

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

    Это так только по случайному стечению обстоятельств на IA32. volatile имеет влияние лишь на код, генерируемый компилятором. На переупорядочивание инструкций процессором он не имеет никакого влияния. Именно по этой причине на всех современных RISC процессорах, а также на IA64, тебе придется использовать барьеры памяти чтобы прочитать актуальное значение.

    > ME> После sequence points, компилятор обязан перечитывать значения переменных из памяти, неважно, volatile ли, const ли, или это переменная без cv-квалификатора

    >
    > С чего бы он вдруг стал обязан? Компилятор обязан лишь обеспечить последовательное выполнение заданных действий в рамках одного потока исполнения. Для взаимодействия с "внешними" процессами и существует volatile.

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

    > Простейший пример:

    >
    >
    > void f (int &a, int &b) {
    >   if (!a) {
    >     b = a;
    >   }
    > }
    >

    >
    > При включенной оптимизации многие компиляторы (например, VC++ 6.0) сгенерируют только один опрос переменной a — в проверке условия. Для присваивания будет сгенерирован явный нуль.

    Здесь именно простейший пример: нет вызовов ф-ций, компилятор видит весь контекст и плевал на sequence points. Добавим вызов ф-ции.

    #include <cstdio>
    
    void f1(int &a, int &b)
    {
         if (!a)
         {
             b = a;
         }
    }
    
    void f2(int volatile &a, int &b)
    {
         if (!a)
         {
             b = a;
         }
    }
    
    void f3(int &a, int &b)
    {
         if (!a)
         {
             printf("0x%08x\n", &a);
             b = a;
         }
    }
    
    int main(int ac, char** av)
    {
         int b;
         f1(ac, b);
         f2(ac, b);
         f3(ac, b);
         return b;
    }


    MS VC 7.1

    Command Lines    
    
    Creating temporary file "c:\windows\temp\Vad43A.bs" with contents
    [
    /c  /Ox /Og /Ob2 /Oi /Ot /Oy /G6 /GF /FD /EHsc /ML /Zc:wchar_t /Zc:forScope /GR /Zi /nologo /W3 /Wp64 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /Fo"Release/" /Fd"Release/vc70.pdb" /Gd /TP
    .\main.cpp
    ]
    Creating command line "cl.exe @c:\windows\temp\Vad43A.bs"
    Creating temporary file "c:\windows\temp\Vad43C.bs" with contents
    [
    /LTCG /OUT:"Release/exp.exe" /INCREMENTAL:NO /DEBUG /PDB:"Release/exp.pdb" /SUBSYSTEM:CONSOLE /OPT:REF /OPT:ICF /TLBID:1 /MACHINE:IX86  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib
    Release\main.obj
    ]
    Creating command line "xilink.exe @c:\windows\temp\Vad43C.bs"


    --- d:\src\exp\main.cpp --------------------------------------------------------
    
    int main(int ac, char** av)
    {
         int b;
         f1(ac, b);
    00401070 8B 4C 24 04      mov         ecx,dword ptr [esp+4] ; сохранили ac в ecx
    00401074 85 C9            test        ecx,ecx
    00401076 75 04            jne         main+0Ch (40107Ch)
    00401078 33 C0            xor         eax,eax
    0040107A EB 04            jmp         main+10h (401080h)
    0040107C 8B 44 24 04      mov         eax,dword ptr [esp+4] ; oops, перечетали ac, видимо такая оптимизация
         f2(ac, b);
    00401080 8B 54 24 04      mov         edx,dword ptr [esp+4] ; еще раз сохранили ac в ecx
    00401084 85 D2            test        edx,edx
    00401086 75 04            jne         main+1Ch (40108Ch)
    00401088 8B 44 24 04      mov         eax,dword ptr [esp+4] ; перечитали ac, так и должно быть, volatile
         f3(ac, b);
    0040108C 85 C9            test        ecx,ecx ; используем сохраненное ac в ecx
    0040108E 75 16            jne         main+36h (4010A6h)
    00401090 8D 44 24 04      lea         eax,[esp+4]
    00401094 50               push        eax
    00401095 68 FC 60 40 00   push        offset string "0x%08x\n" (4060FCh)
    0040109A E8 08 00 00 00   call        printf (4010A7h)
         return b;
    0040109F 8B 44 24 0C      mov         eax,dword ptr [esp+0Ch] ; перечитали ac, так и должно быть, function call
    004010A3 83 C4 08         add         esp,8
    }
    004010A6 C3               ret


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

    > Если к a добавить volatile — будет сгенерировано повторное чтение из памяти. И совершенно правильно.


    С этим никто не спорит.



    Мой point: volatile бесполезен (и даже вреден) для multithreading, барьеры нужны по-любому.

    --
    Maxim Yegorushkin
    Posted via RSDN NNTP Server 1.9
    Re[4]: volatile у переменной класса
    От: MaximE Великобритания  
    Дата: 10.01.05 17:08
    Оценка:
    emusic wrote:

    > Прохождение sequence point отнюдь не гарантирует, что состояния всех объектов в этой точке будут непременно отражены в памяти — это гарантируется только для volatile-объектов.


    Это не гарантируется большинством современных процессоров.

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

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


    Нет именно так как я и написал. Это дословно из MSDN.

    ME>Вообще, квалификатор volatile у всех Interlocked* функций абсолютно бесполезен....


    Поверь мне (если не мне то хотя бы хедерам от WinSDK), очень полезен и стоит там по делу.

    Счастливый, ты еще не "втыкался" в проблемы связанные в hyperthreading по всей видимости.
    Re[5]: volatile у переменной класса
    От: c-smile Канада http://terrainformatica.com
    Дата: 10.01.05 18:38
    Оценка:
    Здравствуйте, MaximE, Вы писали:

    >> Прохождение sequence point отнюдь не гарантирует, что состояния всех объектов в этой точке будут непременно отражены в памяти — это гарантируется только для volatile-объектов.


    ME>Это не гарантируется большинством современных процессоров.


    Т.е. ты утверждаешь что в "большинстве современных процессоров" нет операции
    записи регистра в память? Или я не понял чего.
    Re[4]: volatile у переменной класса
    От: MaximE Великобритания  
    Дата: 10.01.05 18:51
    Оценка:
    c-smile wrote:

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

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

    Sorry, это я ошибся, долбаные MS define'ы...

    > ME>Вообще, квалификатор volatile у всех Interlocked* функций абсолютно бесполезен....

    >
    > Поверь мне (если не мне то хотя бы хедерам от WinSDK), очень полезен и стоит там по делу.
    >
    > Счастливый, ты еще не "втыкался" в проблемы связанные в hyperthreading по всей видимости.

    Еще раз — volatile абсолютно бесполезен для multithreading.

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

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

    >
    >>> Прохождение sequence point отнюдь не гарантирует, что состояния всех объектов в этой точке будут непременно отражены в памяти — это гарантируется только для volatile-объектов.
    >
    > ME>Это не гарантируется большинством современных процессоров.
    >
    > Т.е. ты утверждаешь что в "большинстве современных процессоров" нет операции
    > записи регистра в память? Или я не понял чего.

    Большинство современных процессоров переупорядочивают инструкции. Чтобы запись, сделанная одним процессором, стала видна другому, необходимо применять барьеры памяти. Атомарность инструкций ортогональна.

    Ищи deja.com по ключевым словам "memory visibility"

    --
    Maxim Yegorushkin
    Posted via RSDN NNTP Server 1.9
    Re[6]: volatile у переменной класса
    От: MaximE Великобритания  
    Дата: 10.01.05 19:07
    Оценка:
    emusic wrote:

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

    >
    > ME>Использование любого примитива синхронизации в POSIX и win32 является вызовом ф-ции. Вызов ф-ции — sequence point. Если у тебя уже есть sequence points вокруг защищаемых данных, зачем тогда volatile?
    >
    > Абсолютной необходимости в примитивах синхронизации нет. Если один процесс записывает значения в некоторую ячейку общей памяти, а другой их оттуда читает, и доступ к ячейке на всех поддерживаемых платформах гарантированно атомарный — какой смысл в дополнительных примитивах? Достаточно лишь указать компилятору, что с объектом нужно вести себя более аккуратно, что и делает volatile.

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

    []

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

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

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

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

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

    Ошибаешься. volatile не вставляет никаких барьеров. Барьеры обеспечиваются ф-циями http://msdn.microsoft.com/library/en-us/kmarch/hh/kmarch/Synchro_88127404-a394-403f-a289-d61c45ab81d5.xml.asp

    >>> ME> После sequence points, компилятор обязан перечитывать значения переменных из памяти, неважно, volatile ли, const ли, или это переменная без cv-квалификатора

    >>>
    >>> С чего бы он вдруг стал обязан? Компилятор обязан лишь обеспечить последовательное выполнение заданных действий в рамках одного потока исполнения. Для взаимодействия с "внешними" процессами и существует volatile.

    volatile только для асинхронных обработчиков сигналов.

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

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

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

    []

    > А давай вместо вызова функции добавим модификацию объекта — например, введем переменную c и сделаем ей инкремент:

    >
    >
    >   int c = b;
    >
    >   if (!a) {
    >
    >     c++;
    >
    >     b = a;
    >
    >   }
    >
    >   return c;
    >

    >
    > Модификация объекта, согласно стандарту, есть sequence point. А по соглашениям MS любой оператор также является SP, и условие в if является ею же. Однако это не мешает компилятору по-прежнему использовать константу-нуль.

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

    > ME>Мой point: volatile бесполезен (и даже вреден) для multithreading, барьеры нужны по-любому.

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

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

    > Их там нет — они реализуются средствами платформы.


    Это так.

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


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

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


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

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

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

    >
    > ME>Рихтер ошибался.
    >
    > ME>volatile не имеет никакого отношения к multithreading, поэтому его применение в этой ситуации не только бесполезно, но может быть и вредно, так как с volatile компилятор не сможет соптимизировтать доступ к этой переменной. Но если один из потоков изменяет переменную, синхронизация при помощи мютексов обязательна.
    >
    > Максим, я извиняюсь но вот эти твои высказывания неверны.
    >
    > Для установки значения переменной в другом потоке используетс InterlockedExchange
    > На i386 это две инструкции lock и txchgl.

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

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

    --
    Maxim Yegorushkin
    Posted via RSDN NNTP Server 1.9
    Re: читаем про volatile
    От: MaximE Великобритания  
    Дата: 10.01.05 19:16
    Оценка:
    Вобщем, все вдумчиво читаем.

    --
    Maxim Yegorushkin
    Posted via RSDN NNTP Server 1.9
    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[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[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
    От: 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[4]: volatile у переменной класса
    От: achp  
    Дата: 12.01.05 11:51
    Оценка:
    Здравствуйте, emusic, Вы писали:

    E>А вот при наличии volatile при каждом обращении к такому объекту формируется sequence point.


    Откуда это следует? В стандарте написано, что обращение к volatile-объектам встроенных типов является частью обозримого поведения (observable behaviour) программы, а следовательно не может быть устранено средствами оптимизации. Но это не имеет никакого отношения к точкам следования.
    Я кончил, джентльмены, мне остается только поблагодарить вас за внимание.
    Re[4]: volatile у переменной класса
    От: achp  
    Дата: 12.01.05 12:00
    Оценка:
    Здравствуйте, emusic, Вы писали:

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


    Собственно, в этом их raison d'etre. Иначе мьютексов бы хватало.
    Я кончил, джентльмены, мне остается только поблагодарить вас за внимание.
    Re[5]: volatile у переменной класса
    От: emusic Франция https://software.muzychenko.net/ru
    Дата: 12.01.05 12:06
    Оценка:
    Здравствуйте, achp, Вы писали:

    E>>А вот при наличии volatile при каждом обращении к такому объекту формируется sequence point.


    A>Откуда это следует?


    Тут я спутал — обращение к volatile-объекту стандарт относит к явлениям побочных эффектов.
    ... << RSDN@Home 1.1.4 beta 3 rev. 185>>
    Re[8]: читаем про volatile
    От: Аноним  
    Дата: 12.01.05 12:18
    Оценка:
    ME>За эту статью Александреску был публично выпорон

    Как-то колбасит от этого слова. Выпорон или выпорот?
    Re[10]: volatile у переменной класса
    От: MaximE Великобритания  
    Дата: 14.01.05 18:36
    Оценка:
    Здравствуйте, emusic, Вы писали:

    []

    E>Если тебе удается успешно обходиться без volatile, одними примитивами — это не более, чем случайность. Весьма, впрочем, распространенная ввиду того, что нынешние оптимизаторы в большинстве случаев справедливо опасаются использовать кэшированные ранее значения после вызова неизвестной функции (тот самый aliasing, разговор о котором ты предпочел не развивать). Но, попадись такой код мощному оптимизатору, который не поленится проанализировать вызываемую функцию, или окажись примитивы синхронизации реализованными в более явном виде, этот код нормально работать перестанет. И неожиданным это будет лишь для тебя


    Я скомпилировал следующий код на VC71 и Intel 8 с максимальными настройками оптимизации, с LTCG/IPO и без. Во всех четырех случаях при чтении переменная не кэшировалась, неважно, volatile ли была переменная или нет.

    Оптимизатор, более мощный чем у VC71, мне не известен. Пример прост, и, скорее всего, более легкий пример для оптимизатора сложно придумать.

    Хотелось бы увидеть multithreaded код, где volatile реально чем-то помогает.

    // main.cpp
    
    #include <stdio.h>
    #include "windows.h"
    
    extern void foo();
    
    long a;
    long b;
    long volatile c;
    
    void f()
    {
        while(!a)
            Sleep(20);
        printf("%s is done\n", __FUNCTION__);
    }
    
    void g()
    {
        while(!b)
            Sleep(20);
        printf("%s is done\n", __FUNCTION__);
    }
    
    void h()
    {
        while(!c)
            Sleep(20);
        printf("%s is done\n", __FUNCTION__);
    }
    
    int main()
    {
        foo();
    
        f();
        g();
        h();
    }


    // other.cpp
    
    #include "windows.h"
    
    extern long a;
    extern long b;
    extern long volatile c;
    
    
    DWORD WINAPI thread(void*)
    {
        Sleep(200);
        InterlockedIncrement(&a);
        Sleep(200);
        ++b;
        Sleep(200);
        ++c;
        return 0;
    }
    
    void foo()
    {
        CreateThread(0, 0, thread, 0, 0, 0);
    }


    /c  /Ox /Og /Ob2 /Oi /Ot /Oy /G7 /GF /FD /ML /Zi /nologo /W4 /Wp64 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /FAs /Fa"Release/" /Fo"Release/" /Fd"Release/vc70.pdb" /Gd /TP
    /OUT:"Release/volatile.exe" /INCREMENTAL:NO /DEBUG /PDB:"Release/volatile.pdb" /SUBSYSTEM:CONSOLE /OPT:REF /OPT:ICF /OPT:NOWIN98 /TLBID:1 /MACHINE:IX86  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib 
    
    --- d:\src\volatile\main.cpp ---------------------------------------------------
    
    int main()
    {
    004010C0  push        esi  
        foo();
    004010C1  call        foo (4011A0h) 
    
        f();
    004010C6  cmp         dword ptr [a (4096C8h)],0 
    004010CD  mov         esi,dword ptr [__imp__Sleep@4 (407000h)] 
    004010D3  jne         main+22h (4010E2h) 
    004010D5  push        14h  
    004010D7  call        esi  
    004010D9  cmp         dword ptr [a (4096C8h)],0 
    004010E0  je          main+15h (4010D5h) 
    004010E2  push        offset string "f" (407108h) 
    004010E7  push        offset string "%s is done\n" (4070FCh) 
    004010EC  call        printf (4011B6h) 
    004010F1  add         esp,8 
        g();
    004010F4  cmp         dword ptr [b (4096C0h)],0 
    004010FB  jne         main+4Dh (40110Dh) 
    004010FD  lea         ecx,[ecx] 
    00401100  push        14h  
    00401102  call        esi  
    00401104  cmp         dword ptr [b (4096C0h)],0 
    0040110B  je          main+40h (401100h) 
    0040110D  push        offset string "g" (40710Ch) 
    00401112  push        offset string "%s is done\n" (4070FCh) 
    00401117  call        printf (4011B6h) 
    0040111C  add         esp,8 
        h();
    0040111F  cmp         dword ptr [c (4096C4h)],0 
    00401126  jne         main+75h (401135h) 
    00401128  push        14h  
    0040112A  call        esi  
    0040112C  cmp         dword ptr [c (4096C4h)],0 
    00401133  je          main+68h (401128h) 
    00401135  push        offset string "h" (407110h) 
    0040113A  push        offset string "%s is done\n" (4070FCh) 
    0040113F  call        printf (4011B6h) 
    00401144  add         esp,8 
    }
    00401147  xor         eax,eax 
    00401149  pop         esi  
    0040114A  ret              
    --- No source file -------------------------------------------------------------
    0040114B  int         3    
    0040114C  int         3    
    0040114D  int         3    
    0040114E  int         3    
    0040114F  int         3    
    --- d:\src\volatile\other.cpp --------------------------------------------------
    #include "windows.h"
    
    extern long a;
    extern long b;
    extern long volatile c;
    
    
    DWORD WINAPI thread(void*)
    {
    00401150  push        esi  
        Sleep(200);
    00401151  mov         esi,dword ptr [__imp__Sleep@4 (407000h)] 
    00401157  push        0C8h 
    0040115C  call        esi  
        InterlockedIncrement(&a);
    0040115E  push        offset a (4096C8h) 
    00401163  call        dword ptr [__imp__InterlockedIncrement@4 (407004h)] 
        Sleep(200);
    00401169  push        0C8h 
    0040116E  call        esi  
        ++b;
    00401170  add         dword ptr [b (4096C0h)],1 
        Sleep(200);
    00401177  push        0C8h 
    0040117C  call        esi  
        ++c;
    0040117E  mov         eax,dword ptr [c (4096C4h)] 
    00401183  add         eax,1 
    00401186  mov         dword ptr [c (4096C4h)],eax 
        return 0;
    0040118B  xor         eax,eax 
    0040118D  pop         esi  
    }
    0040118E  ret         4


    /c  /Ox /Og /Ob2 /Oi /Ot /Oy /G7 /GF /FD /ML /Zi /nologo /W4 /Wp64 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /FAs /Fa"Release/" /Fo"Release/" /Fd"Release/vc70.pdb" /Gd /TP
    /LTCG /OUT:"Release/volatile.exe" /INCREMENTAL:NO /DEBUG /PDB:"Release/volatile.pdb" /SUBSYSTEM:CONSOLE /OPT:REF /OPT:ICF /OPT:NOWIN98 /TLBID:1 /MACHINE:IX86  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib 
    
    --- d:\src\volatile\main.cpp ---------------------------------------------------
    
    int main()
    {
    004010C0  push        esi  
        foo();
    004010C1  call        foo (4011A0h) 
    
        f();
    004010C6  cmp         dword ptr [a (4096C8h)],0 
    004010CD  mov         esi,dword ptr [__imp__Sleep@4 (407000h)] 
    004010D3  jne         main+22h (4010E2h) 
    004010D5  push        14h  
    004010D7  call        esi  
    004010D9  cmp         dword ptr [a (4096C8h)],0 
    004010E0  je          main+15h (4010D5h) 
    004010E2  push        offset string "f" (407108h) 
    004010E7  push        offset string "%s is done\n" (4070FCh) 
    004010EC  call        printf (4011B6h) 
    004010F1  add         esp,8 
        g();
    004010F4  cmp         dword ptr [b (4096C0h)],0 
    004010FB  jne         main+4Dh (40110Dh) 
    004010FD  lea         ecx,[ecx] 
    00401100  push        14h  
    00401102  call        esi  
    00401104  cmp         dword ptr [b (4096C0h)],0 
    0040110B  je          main+40h (401100h) 
    0040110D  push        offset string "g" (40710Ch) 
    00401112  push        offset string "%s is done\n" (4070FCh) 
    00401117  call        printf (4011B6h) 
    0040111C  add         esp,8 
        h();
    0040111F  cmp         dword ptr [c (4096C4h)],0 
    00401126  jne         main+75h (401135h) 
    00401128  push        14h  
    0040112A  call        esi  
    0040112C  cmp         dword ptr [c (4096C4h)],0 
    00401133  je          main+68h (401128h) 
    00401135  push        offset string "h" (407110h) 
    0040113A  push        offset string "%s is done\n" (4070FCh) 
    0040113F  call        printf (4011B6h) 
    00401144  add         esp,8 
    }
    00401147  xor         eax,eax 
    00401149  pop         esi  
    0040114A  ret              
    --- No source file -------------------------------------------------------------
    0040114B  int         3    
    0040114C  int         3    
    0040114D  int         3    
    0040114E  int         3    
    0040114F  int         3    
    --- d:\src\volatile\other.cpp --------------------------------------------------
    #include "windows.h"
    
    extern long a;
    extern long b;
    extern long volatile c;
    
    
    DWORD WINAPI thread(void*)
    {
    00401150  push        esi  
        Sleep(200);
    00401151  mov         esi,dword ptr [__imp__Sleep@4 (407000h)] 
    00401157  push        0C8h 
    0040115C  call        esi  
        InterlockedIncrement(&a);
    0040115E  push        offset a (4096C8h) 
    00401163  call        dword ptr [__imp__InterlockedIncrement@4 (407004h)] 
        Sleep(200);
    00401169  push        0C8h 
    0040116E  call        esi  
        ++b;
    00401170  add         dword ptr [b (4096C0h)],1 
        Sleep(200);
    00401177  push        0C8h 
    0040117C  call        esi  
        ++c;
    0040117E  mov         eax,dword ptr [c (4096C4h)] 
    00401183  add         eax,1 
    00401186  mov         dword ptr [c (4096C4h)],eax 
        return 0;
    0040118B  xor         eax,eax 
    0040118D  pop         esi  
    }
    0040118E  ret         4


    /c /Qvc7.1 /Qlocation,link,"C:\Program Files\Microsoft Visual Studio .NET 2003\Vc7/bin"  /Ox /Og /Ob2 /Oi /Ot /Oy /G7 /GF /FD /ML /Zi /nologo /W4 /Wp64 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /FAs /Fa"Release/" /Fo"Release/" /Fd"Release/vc70.pdb" /Gd /TP
    /OUT:"Release/volatile.exe" /INCREMENTAL:NO /DEBUG /PDB:"Release/volatile.pdb" /SUBSYSTEM:CONSOLE /OPT:REF /OPT:ICF /OPT:NOWIN98 /TLBID:1 /MACHINE:IX86  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib 
    
    --- .\main.cpp -----------------------------------------------------------------
    
    int main()
    {
    00401000  push        ebx  
    00401001  mov         ebx,esp 
    00401003  and         esp,0FFFFFFF0h 
    00401006  call        ___intel_proc_init (4060A4h) 
        foo();
    0040100B  call        foo (401164h) 
    
        f();
    00401010  mov         eax,dword ptr [a (4096C8h)] 
    00401015  test        eax,eax 
    00401017  jne         main+2Ah (40102Ah) 
    00401019  push        14h  
    0040101B  call        dword ptr [__imp__Sleep@4 (407000h)] 
    00401021  mov         eax,dword ptr [a (4096C8h)] 
    00401026  test        eax,eax 
    00401028  je          main+19h (401019h) 
    0040102A  push        offset KERNEL32_NULL_THUNK_DATA+28h (407104h) 
    0040102F  push        offset string "%s is done\n" (407114h) 
    00401034  call        printf (401178h) 
    00401039  add         esp,8 
        g();
    0040103C  mov         eax,dword ptr [b (4096C4h)] 
    00401041  test        eax,eax 
    00401043  jne         main+56h (401056h) 
    00401045  push        14h  
    00401047  call        dword ptr [__imp__Sleep@4 (407000h)] 
    0040104D  mov         eax,dword ptr [b (4096C4h)] 
    00401052  test        eax,eax 
    00401054  je          main+45h (401045h) 
    00401056  push        offset KERNEL32_NULL_THUNK_DATA+24h (407100h) 
    0040105B  push        offset string "%s is done\n" (407114h) 
    00401060  call        printf (401178h) 
    00401065  add         esp,8 
        h();
    00401068  mov         eax,dword ptr [c (4096C0h)] 
    0040106D  test        eax,eax 
    0040106F  jne         main+82h (401082h) 
    00401071  push        14h  
    00401073  call        dword ptr [__imp__Sleep@4 (407000h)] 
    00401079  mov         eax,dword ptr [c (4096C0h)] 
    0040107E  test        eax,eax 
    00401080  je          main+71h (401071h) 
    00401082  push        offset KERNEL32_NULL_THUNK_DATA+20h (4070FCh) 
    00401087  push        offset string "%s is done\n" (407114h) 
    0040108C  call        printf (401178h) 
    00401091  add         esp,8 
    }
    00401094  xor         eax,eax 
    00401096  mov         esp,ebx 
    00401098  pop         ebx  
    00401099  ret              
    #include <stdio.h>
    #include "windows.h"
    
    extern void foo();
    
    long a;
    long b;
    long volatile c;
    
    void f()
    {
        while(!a)
    0040109A  mov         eax,dword ptr [a (4096C8h)] 
    0040109F  test        eax,eax 
    004010A1  jne         f+1Ah (4010B4h) 
            Sleep(20);
    004010A3  push        14h  
    004010A5  call        dword ptr [__imp__Sleep@4 (407000h)] 
    #include <stdio.h>
    #include "windows.h"
    
    extern void foo();
    
    long a;
    long b;
    long volatile c;
    
    void f()
    {
        while(!a)
    004010AB  mov         eax,dword ptr [a (4096C8h)] 
    004010B0  test        eax,eax 
    004010B2  je          f+9 (4010A3h) 
        printf("%s is done\n", __FUNCTION__);
    004010B4  push        offset KERNEL32_NULL_THUNK_DATA+2Ch (407108h) 
    004010B9  push        offset string "%s is done\n" (407114h) 
    004010BE  call        printf (401178h) 
    }
    004010C3  add         esp,8 
    004010C6  ret              
    004010C7  nop              
    
    void g()
    {
        while(!b)
    004010C8  mov         eax,dword ptr [b (4096C4h)] 
    004010CD  test        eax,eax 
    004010CF  jne         g+1Ah (4010E2h) 
            Sleep(20);
    004010D1  push        14h  
    004010D3  call        dword ptr [__imp__Sleep@4 (407000h)] 
    
    void g()
    {
        while(!b)
    004010D9  mov         eax,dword ptr [b (4096C4h)] 
    004010DE  test        eax,eax 
    004010E0  je          g+9 (4010D1h) 
        printf("%s is done\n", __FUNCTION__);
    004010E2  push        offset KERNEL32_NULL_THUNK_DATA+30h (40710Ch) 
    004010E7  push        offset string "%s is done\n" (407114h) 
    004010EC  call        printf (401178h) 
    }
    004010F1  add         esp,8 
    004010F4  ret              
    004010F5  nop              
    
    void h()
    {
        while(!c)
    004010F6  mov         eax,dword ptr [c (4096C0h)] 
    004010FB  test        eax,eax 
    004010FD  jne         h+1Ah (401110h) 
            Sleep(20);
    004010FF  push        14h  
    00401101  call        dword ptr [__imp__Sleep@4 (407000h)] 
    
    void h()
    {
        while(!c)
    00401107  mov         eax,dword ptr [c (4096C0h)] 
    0040110C  test        eax,eax 
    0040110E  je          h+9 (4010FFh) 
        printf("%s is done\n", __FUNCTION__);
    00401110  push        offset KERNEL32_NULL_THUNK_DATA+34h (407110h) 
    00401115  push        offset string "%s is done\n" (407114h) 
    0040111A  call        printf (401178h) 
    }
    0040111F  add         esp,8 
    00401122  ret              
    00401123  nop              
    --- .\other.cpp ----------------------------------------------------------------
    #include "windows.h"
    
    extern long a;
    extern long b;
    extern long volatile c;
    
    
    DWORD WINAPI thread(void*)
    {
        Sleep(200);
    00401124  push        0C8h 
    00401129  call        dword ptr [__imp__Sleep@4 (407000h)] 
        InterlockedIncrement(&a);
    0040112F  push        offset a (4096C8h) 
    00401134  call        dword ptr [__imp__InterlockedIncrement@4 (407004h)] 
        Sleep(200);
    0040113A  push        0C8h 
    0040113F  call        dword ptr [__imp__Sleep@4 (407000h)] 
        ++b;
    00401145  add         dword ptr [b (4096C4h)],1 
        Sleep(200);
    0040114C  push        0C8h 
    00401151  call        dword ptr [__imp__Sleep@4 (407000h)] 
        ++c;
    00401157  add         dword ptr [c (4096C0h)],1 
        return 0;
    0040115E  xor         eax,eax 
    00401160  ret         4    
    00401163  nop              
    }
    
    void foo()
    {
        CreateThread(0, 0, thread, 0, 0, 0);
    00401164  xor         eax,eax 
    00401166  push        eax  
    00401167  push        eax  
    00401168  push        eax  
    00401169  push        offset thread (401124h) 
    0040116E  push        eax  
    0040116F  push        eax  
    00401170  call        dword ptr [__imp__CreateThread@24 (407008h)] 
    }
    00401176  ret              
    00401177  nop


    /c /Qvc7.1 /Qlocation,link,"C:\Program Files\Microsoft Visual Studio .NET 2003\Vc7/bin"  /GL /Ox /Og /Ob2 /Oi /Ot /Oy /G7 /GF /FD /ML /Zi /nologo /W4 /Wp64 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /FAs /Fa"Release/" /Fo"Release/" /Fd"Release/vc70.pdb" /Gd /TP
    /LTCG /OUT:"Release/volatile.exe" /INCREMENTAL:NO /DEBUG /PDB:"Release/volatile.pdb" /SUBSYSTEM:CONSOLE /OPT:REF /OPT:ICF /OPT:NOWIN98 /TLBID:1 /MACHINE:IX86  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib 
    
    --- .\main.cpp -----------------------------------------------------------------
    #include <stdio.h>
    #include "windows.h"
    
    extern void foo();
    
    long a;
    long b;
    long volatile c;
    
    void f()
    {
        while(!a)
            Sleep(20);
        printf("%s is done\n", __FUNCTION__);
    }
    
    void g()
    {
        while(!b)
            Sleep(20);
        printf("%s is done\n", __FUNCTION__);
    }
    
    void h()
    {
        while(!c)
            Sleep(20);
        printf("%s is done\n", __FUNCTION__);
    }
    
    int main()
    {
    00401000  push        ebx  
    00401001  mov         ebx,esp 
    00401003  and         esp,0FFFFFFF0h 
    00401006  call        ___intel_proc_init (406014h) 
        foo();
    0040100B  call        foo (40109Ah) 
    
        f();
    00401010  mov         eax,dword ptr [___decimal_point_length+174h (4096C0h)] 
    00401015  test        eax,eax 
    00401017  jne         main+2Ah (40102Ah) 
    00401019  push        14h  
    0040101B  call        dword ptr [__imp__Sleep@4 (407000h)] 
    00401021  mov         eax,dword ptr [___decimal_point_length+174h (4096C0h)] 
    00401026  test        eax,eax 
    00401028  je          main+19h (401019h) 
    0040102A  push        offset KERNEL32_NULL_THUNK_DATA+28h (407104h) 
    0040102F  push        offset KERNEL32_NULL_THUNK_DATA+2Ch (407108h) 
    00401034  call        printf (4010F4h) 
    00401039  add         esp,8 
        g();
    0040103C  mov         eax,dword ptr [___decimal_point_length+178h (4096C4h)] 
    00401041  test        eax,eax 
    00401043  jne         main+56h (401056h) 
    00401045  push        14h  
    00401047  call        dword ptr [__imp__Sleep@4 (407000h)] 
    0040104D  mov         eax,dword ptr [___decimal_point_length+178h (4096C4h)] 
    00401052  test        eax,eax 
    00401054  je          main+45h (401045h) 
    00401056  push        offset KERNEL32_NULL_THUNK_DATA+24h (407100h) 
    0040105B  push        offset KERNEL32_NULL_THUNK_DATA+2Ch (407108h) 
    00401060  call        printf (4010F4h) 
    00401065  add         esp,8 
        h();
    00401068  mov         eax,dword ptr [___decimal_point_length+17Ch (4096C8h)] 
    0040106D  test        eax,eax 
    0040106F  jne         main+82h (401082h) 
    00401071  push        14h  
    00401073  call        dword ptr [__imp__Sleep@4 (407000h)] 
    00401079  mov         eax,dword ptr [___decimal_point_length+17Ch (4096C8h)] 
    0040107E  test        eax,eax 
    00401080  je          main+71h (401071h) 
    00401082  push        offset KERNEL32_NULL_THUNK_DATA+20h (4070FCh) 
    00401087  push        offset KERNEL32_NULL_THUNK_DATA+2Ch (407108h) 
    0040108C  call        printf (4010F4h) 
    00401091  add         esp,8 
    }
    00401094  xor         eax,eax 
    00401096  mov         esp,ebx 
    00401098  pop         ebx  
    00401099  ret              
    --- .\other.cpp ----------------------------------------------------------------
    }
    
    void foo()
    {
    0040109A  sub         esp,0Ch 
        CreateThread(0, 0, thread, 0, 0, 0);
    0040109D  xor         eax,eax 
    0040109F  push        eax  
    004010A0  push        eax  
    004010A1  push        eax  
    004010A2  push        offset thread (4010B4h) 
    004010A7  push        eax  
    004010A8  push        eax  
    004010A9  call        dword ptr [__imp__CreateThread@24 (407004h)] 
    }
    004010AF  add         esp,0Ch 
    004010B2  ret              
    004010B3  nop              
    #include "windows.h"
    
    extern long a;
    extern long b;
    extern long volatile c;
    
    
    DWORD WINAPI thread(void*)
    {
        Sleep(200);
    004010B4  push        0C8h 
    004010B9  call        dword ptr [__imp__Sleep@4 (407000h)] 
        InterlockedIncrement(&a);
    004010BF  push        offset ___decimal_point_length+174h (4096C0h) 
    004010C4  call        dword ptr [__imp__InterlockedIncrement@4 (407008h)] 
        Sleep(200);
    004010CA  push        0C8h 
    004010CF  call        dword ptr [__imp__Sleep@4 (407000h)] 
        ++b;
    004010D5  add         dword ptr [___decimal_point_length+178h (4096C4h)],1 
        Sleep(200);
    004010DC  push        0C8h 
    004010E1  call        dword ptr [__imp__Sleep@4 (407000h)] 
        ++c;
    004010E7  add         dword ptr [___decimal_point_length+17Ch (4096C8h)],1 
        return 0;
    004010EE  xor         eax,eax 
    004010F0  ret         4    
    004010F3  nop
    Re[11]: volatile у переменной класса
    От: achp  
    Дата: 14.01.05 19:30
    Оценка:
    Здравствуйте, MaximE, Вы писали:

    ME>Я скомпилировал следующий код на VC71 и Intel 8 с максимальными настройками оптимизации, с LTCG/IPO и без. Во всех четырех случаях при чтении переменная не кэшировалась, неважно, volatile ли была переменная или нет.


    Возможно, дело в вызовах Sleep; компилятор не имеет возможности проверить, не изменяет ли Sleep переменные, поэтому генерирует код из предположения, что переменная там может измениться.
    Я кончил, джентльмены, мне остается только поблагодарить вас за внимание.
    Re[11]: volatile у переменной класса
    От: emusic Франция https://software.muzychenko.net/ru
    Дата: 15.01.05 13:28
    Оценка:
    Здравствуйте, MaximE, Вы писали:

    ME>Я скомпилировал следующий код на VC71 и Intel 8 с максимальными настройками оптимизации, с LTCG/IPO и без.


    В этих примерах используются глобальные переменные, и глобальные же функции. Откуда оптимизатору знать, что функция Sleep не изменяет этих переменных?

    Если переделать все переменные и функции на статические, и добавить ключ запрета aliasing'а — оптимизатор вполне может начать кэшировать значения. Хотя в VC++ 7.0 оптимизатор это делать ленится.

    ME>Хотелось бы увидеть multithreaded код, где volatile реально чем-то помогает.


    Я уже приводил такой код. Приведу в более убедительном виде:

    #include <windows.h>
    
    CRITICAL_SECTION CS;
    
    int f (int *a, int *b) {
      EnterCriticalSection (&CS);
      if (!*a) {
        LeaveCriticalSection (&CS);
        Sleep (100);
        EnterCriticalSection (&CS);
        *b = *a;
      }
      LeaveCriticalSection (&CS);
      return *b;
    }


    Если скомпилить его VC++ 6/7 с ключом /Oa — в присваивании внутри условия используется константа 0. Разумеется, код притянут за уши, но он наглядно показывает, что оптимизатор может кэшировать значение объекта, если у того нет volatile. aliasing'а в данном примере нет — нигде в программе другого доступа к объектам *a и *b быть не обязано. Без параллелизма данный код будет работать всегда. С параллелизмом — сам догадайся

    Большинство примеров кода без volatile работает в многопоточной среде только за счет того, что компилятор до последнего подозревает о наличии этого самого aliasing'а — что любая из вызываемых функций, код которой нельзя проанализировать сейчас же, потенциально может изменить переменную через указатель на нее. Именно поэтому после вызова функций переменные перечитываются, а отнюдь не из-за sequience points.
    ... << RSDN@Home 1.1.4 beta 3 rev. 185>>
    Re[12]: volatile у переменной класса
    От: Шахтер Интернет  
    Дата: 15.01.05 13:39
    Оценка:
    Здравствуйте, emusic, Вы писали:

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


    ME>>Я скомпилировал следующий код на VC71 и Intel 8 с максимальными настройками оптимизации, с LTCG/IPO и без.


    E>В этих примерах используются глобальные переменные, и глобальные же функции. Откуда оптимизатору знать, что функция Sleep не изменяет этих переменных?


    E>Если переделать все переменные и функции на статические, и добавить ключ запрета aliasing'а — оптимизатор вполне может начать кэшировать значения. Хотя в VC++ 7.0 оптимизатор это делать ленится.


    ME>>Хотелось бы увидеть multithreaded код, где volatile реально чем-то помогает.


    E>Я уже приводил такой код. Приведу в более убедительном виде:


    E>
    E>#include <windows.h>
    
    E>CRITICAL_SECTION CS;
    
    E>int f (int *a, int *b) {
    E>  EnterCriticalSection (&CS);
    E>  if (!*a) {
    E>    LeaveCriticalSection (&CS);
    E>    Sleep (100);
    E>    EnterCriticalSection (&CS);
    E>    *b = *a;
    E>  }
    E>  LeaveCriticalSection (&CS);
    E>  return *b;
    E>}
    E>


    E>Если скомпилить его VC++ 6/7 с ключом /Oa — в присваивании внутри условия используется константа 0. Разумеется, код притянут за уши, но он наглядно показывает, что оптимизатор может кэшировать значение объекта, если у того нет volatile. aliasing'а в данном примере нет — нигде в программе другого доступа к объектам *a и *b быть не обязано. Без параллелизма данный код будет работать всегда. С параллелизмом — сам догадайся


    E>Большинство примеров кода без volatile работает в многопоточной среде только за счет того, что компилятор до последнего подозревает о наличии этого самого aliasing'а — что любая из вызываемых функций, код которой нельзя проанализировать сейчас же, потенциально может изменить переменную через указатель на нее. Именно поэтому после вызова функций переменные перечитываются, а отнюдь не из-за sequience points.


    Погоди. Тут что-то не так. a или b вполне могут указывать внутрь критической секции. В этом случае оптимизация незаконна.
    ... << RSDN@Home 1.1.0 stable >>
    В XXI век с CCore.
    Копай Нео, копай -- летать научишься. © Matrix. Парадоксы
    Re[14]: volatile у переменной класса
    От: MaximE Великобритания  
    Дата: 15.01.05 14:24
    Оценка:
    Шахтер wrote:

    > ME>Чтение из памяти на текущих процессорах Intel гарантировано прочитает актуальное значение, даже если память была изменена в кэше другого процессора, т.к. Intel для текущих процессоров применяет cache snooping. ...

    >
    > А какое это отношение имеет к обсуждаемому вопросу? volatile -- это средство ограничения оптимизации кода. Пример того, как оно работает, был приведён выше. К тому, что происходит в
    процессоре, это не имеет никакого отношения.

    Тема была о volatile и multithreading.

    --
    Maxim Yegorushkin
    Posted via RSDN NNTP Server 1.9
    Re[12]: volatile у переменной класса
    От: MaximE Великобритания  
    Дата: 15.01.05 14:30
    Оценка:
    emusic wrote:

    []

    > Если скомпилить его VC++ 6/7 с ключом /Oa — в присваивании внутри условия используется константа 0. Разумеется, код притянут за уши, но он наглядно показывает, что оптимизатор может кэшировать значение объекта, если у того нет volatile. aliasing'а в данном примере нет — нигде в программе другого доступа к объектам *a и *b быть не обязано. Без параллелизма данный код будет работать всегда. С параллелизмом — сам догадайся


    Я про это и пишу:

    Так что volatile не является ни необходимым, ни достаточным для multithreading. Если малтитредовой проге необходим volatile чтобы корректно работать, такая программа непортабельна.


    > Большинство примеров кода без volatile работает в многопоточной среде только за счет того, что компилятор до последнего подозревает о наличии этого самого aliasing'а — что любая из вызываемых функций, код которой нельзя проанализировать сейчас же, потенциально может изменить переменную через указатель на нее. Именно поэтому после вызова функций переменные перечитываются, а отнюдь не из-за sequience points.


    Да, с этим я согласен, про sequience points, похоже, я херню написал.

    --
    Maxim Yegorushkin
    Posted via RSDN NNTP Server 1.9
    Re[13]: volatile у переменной класса
    От: emusic Франция https://software.muzychenko.net/ru
    Дата: 15.01.05 16:20
    Оценка:
    Здравствуйте, Шахтер, Вы писали:

    Ш>Погоди. Тут что-то не так. a или b вполне могут указывать внутрь критической секции. В этом случае оптимизация незаконна.


    Мне сколько раз нужно повторить слово aliasing, чтобы оно было, наконец, воспринято? Указание ключа /Oa сообщает компилятору, что в программе подобные совмещения исключены.
    ... << RSDN@Home 1.1.4 beta 3 rev. 185>>
    Re[3]: volatile у переменной класса
    От: MaximE Великобритания  
    Дата: 15.01.05 23:57
    Оценка:
    Tom wrote:

    []

    > Абсолютно неверный и опасный совет. Как раз volatile тут необходим, как в прочем и желательна защита обьекта при помощи примитивов синхронизации. volatile нужен дабы избежать лишней оптимизации (компилятор может моложить переменную в регистр, и защищая её или нет, но другой поток об том, что переменная изменилась — не узнает никогда, или несвоевременно)


    Почитай топик от начала до конца.

    --
    Maxim Yegorushkin
    Posted via RSDN NNTP Server 1.9
    Re[14]: volatile у переменной класса
    От: MaximE Великобритания  
    Дата: 16.01.05 00:08
    Оценка:
    emusic wrote:

    > Ш>Погоди. Тут что-то не так. a или b вполне могут указывать внутрь критической секции. В этом случае оптимизация незаконна.

    >
    > Мне сколько раз нужно повторить слово aliasing, чтобы оно было, наконец, воспринято? Указание ключа /Oa сообщает компилятору, что в программе подобные совмещения исключены.

    ... но на самом деле они у тебя в проге есть и ты полагаешься на результат этого альясинга. Ты сообщил компилятору неверную информацию — all bets are off.

    --
    Maxim Yegorushkin
    Posted via RSDN NNTP Server 1.9
    Re[15]: volatile у переменной класса
    От: c-smile Канада http://terrainformatica.com
    Дата: 16.01.05 00:37
    Оценка:
    Здравствуйте, MaximE, Вы писали:

    ME>Весь мир давно заездил эту тему до дыр, только до rsdn прогрессивная мысль никак не доберется (.


    Макс, это уже не смешно.
    Или давай технические спеки или ссылки на докуметнацию компиляторов.
    Короче что-нибудь, но не ссылки на threads в дискуссиях ведущихся анонимными авторами.

    "Весь мир давно заездил эту тему" ты имеешь ввиду себя и пару тройку "просвященных"?
    Примерно 25% этого мира посещяет RSDN на котором мы видим "луч света в темном царстве" в твоем лице.

    Чего ты уперся? volatile is a C++ keyword. Period.

    http://www.embedded.com/story/OEG20010615S0107
    Re[4]: [2]: : volatile: а можно примеры?
    От: Шахтер Интернет  
    Дата: 18.01.05 03:12
    Оценка:
    Здравствуйте, eao197, Вы писали:

    E>Максим, я разделяю вашу точку зрения.


    E>Но мне интересно, когда уважаемые emusic, Шахтер, c-smile (извините, если не всех перечислил), отстаивали противоположное мнение, они имели в виду конкретные примеры из собственного опыта или из литературы, или это их интерпритация стардартов и спецификаций? Если примеры есть, то мне было бы очень интересно про них узнать, чтобы не повторять чужих ошибок.


    E>Предложение: давайте не превращать эту ветвь в очередное выяснение истины. Если есть примеры -- приводите, пожалуйста. Если нет, то будем считать это доказательством правильности позиции Максима


    Они уже приведены.
    ... << RSDN@Home 1.1.0 stable >>
    В XXI век с CCore.
    Копай Нео, копай -- летать научишься. © Matrix. Парадоксы
    Re[5]: [2]: : volatile: а можно примеры?
    От: MaximE Великобритания  
    Дата: 18.01.05 05:14
    Оценка:
    Шахтер wrote:

    []

    > E>Предложение: давайте не превращать эту ветвь в очередное выяснение истины. Если есть примеры -- приводите, пожалуйста. Если нет, то будем считать это доказательством правильности позиции Максима

    >
    > Они уже приведены.

    Ok, я не прав был в семантике volatile, привел не удачный пример, и прогнал про sequence points.

    Мой поинт был в том (если этого до сих пор непонятно уважаемому Шахтеру), что какой бы семантикой не обладал volatile, ее просто не достаточно для multithreading, и поэтому volatile бесполезен для multithreading.

    --
    Maxim Yegorushkin
    Posted via RSDN NNTP Server 1.9
    Re[7]: [2]: : volatile: а можно примеры?
    От: MaximE Великобритания  
    Дата: 18.01.05 05:28
    Оценка:
    Odi$$ey wrote:

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

    >
    > ME>Мой поинт был в том (если этого до сих пор непонятно уважаемому Шахтеру), что какой бы семантикой не обладал volatile, ее просто не достаточно для multithreading, и поэтому volatile бесполезен для multithreading.
    >
    > не вдаваясь в технические подробности, из "недостаточно" никак не может следовать "и поэтому ... бесполезен"

    На этом основании ты хочешь объявить все написанное здесь ересью и провозгласить, что volatile необходим и достаточен для обеспечиния синхронизации при multithreading?

    --
    Maxim Yegorushkin
    Posted via RSDN NNTP Server 1.9
    Re[9]: [2]: : volatile: а можно примеры?
    От: MaximE Великобритания  
    Дата: 18.01.05 07:19
    Оценка:
    Odi$$ey wrote:

    []

    > а вот "недостаточно" "и поэтому ... бесполезен" — это действительно ересь хотя бы с точки зрения формальной логики


    Согласен, но с точки зрения треда — это оффтопик.

    --
    Maxim Yegorushkin
    Posted via RSDN NNTP Server 1.9
    Re[4]: volatile у переменной класса
    От: Tom Россия http://www.RSDN.ru
    Дата: 18.01.05 08:57
    Оценка:
    ME>Почитай топик от начала до конца.
    Издеваешься? Там толпа мыслей и доводов. Если есть что — говори тут
    Народная мудрось
    всем все никому ничего(с).
    Реальный пример использования volatile
    От: What Беларусь  
    Дата: 18.01.05 09:00
    Оценка:
    Здравствуйте, eao197, Вы писали:

    E>В связи с этим у меня вопрос: можно ли услышать/увидеть реальные примеры того, как в многопоточных приложениях обнаруживались проблемы из-за того, что не использовалось volatile? Именно реальные, хорошо бы с примерами, хотя бы псевдокода. И не драйверов или софта для работы с железом, а "прикладного" кода.


    Достаточно часто реально используется следующая схема.
    Есть рабочий поток, который в цикле выполняет интенсивные вычисления. Рабочий поток периодически опрашивает состояние глобальной переменной и, если всё ок, продолжает работать, иначе останавливается. Если пользователь решил отменить действие, GUI-поток меняет значение этой переменной.
    #include <iostream>
    #include <process.h>
    #include <windows.h>
    
    /*volatile*/ bool go = true;
    const unsigned int MaxIter = 1000000000;
    
    // Эта процедура выполняет интенсивный вычисления.
    unsigned int __stdcall Calc(void *)
    {
        double sum = 0.0;
        for (unsigned int i = MaxIter; (i != 0) && go; --i)
            sum += 1. / i;
        std::cout << "sum = " << sum << std::endl;
        return 0;
    };
    
    int main()
    {
        unsigned int id;
        HANDLE h = reinterpret_cast<HANDLE>(_beginthreadex(NULL, 0,  &Calc, NULL, 0, &id));
        // Пользователь подумал 20 миллисекунд
        ::Sleep(20);
        // .. и решил отменить вычисления
        go = false;
        ::WaitForSingleObject(h, INFINITE);
        ::CloseHandle(h);
        return 0;
    }


    Так вот, когда volatile закомментирован, то рабочий поток не останавливается программа выводит:

    21.3005


    А когда volatile есть, поток останавливается и программа выводит:

    0.00287083


    Компилятор VC 7.1. Командная строка:
    /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /FD /EHsc
    /MD /GS /Fo"Release/" /Fd"Release/vc70.pdb" /W3 /nologo /c /Wp64 /Zi /TP
    ... << RSDN@Home 1.1.4 beta 3 rev. 185>>
    Re[5]: volatile у переменной класса
    От: MaximE Великобритания  
    Дата: 18.01.05 09:25
    Оценка:
    Tom wrote:

    > ME>Почитай топик от начала до конца.

    > Издеваешься? Там толпа мыслей и доводов. Если есть что — говори тут

    Т.е. ты взял и не читая ляпнул?

    http://www.rsdn.ru/forum/?mid=989456
    Автор: MaximE
    Дата: 16.01.05

    http://www.rsdn.ru/forum/?mid=988910
    Автор: MaximE
    Дата: 15.01.05

    http://www.rsdn.ru/forum/?mid=991653
    Автор: MaximE
    Дата: 17.01.05


    --
    Maxim Yegorushkin
    Posted via RSDN NNTP Server 1.9
    Re: Реальный пример использования volatile
    От: eao197 Беларусь http://eao197.blogspot.com
    Дата: 18.01.05 09:48
    Оценка:
    Здравствуйте, What, Вы писали:

    Но ведь здесь не используются примитивы синхронизации! С моей точки зрения, это как раз опасная практика -- изменять значение в одном потоке без блокирования чтения из другого потока.

    Если бы вы использовали синхронизацию доступа к go, то volatile, наверняка, не потребовался бы.

    W>Достаточно часто реально используется следующая схема.

    W>Есть рабочий поток, который в цикле выполняет интенсивные вычисления. Рабочий поток периодически опрашивает состояние глобальной переменной и, если всё ок, продолжает работать, иначе останавливается. Если пользователь решил отменить действие, GUI-поток меняет значение этой переменной.
    W>
    W>#include <iostream>
    W>#include <process.h>
    W>#include <windows.h>
    
    W>/*volatile*/ bool go = true;
    W>const unsigned int MaxIter = 1000000000;
    
    W>// Эта процедура выполняет интенсивный вычисления.
    W>unsigned int __stdcall Calc(void *)
    W>{
    W>    double sum = 0.0;
    W>    for (unsigned int i = MaxIter; (i != 0) && go; --i)
    W>        sum += 1. / i;
    W>    std::cout << "sum = " << sum << std::endl;
    W>    return 0;
    W>};
    
    W>int main()
    W>{
    W>    unsigned int id;
    W>    HANDLE h = reinterpret_cast<HANDLE>(_beginthreadex(NULL, 0,  &Calc, NULL, 0, &id));
    W>    // Пользователь подумал 20 миллисекунд
    W>    ::Sleep(20);
    W>    // .. и решил отменить вычисления
    W>    go = false;
    W>    ::WaitForSingleObject(h, INFINITE);
    W>    ::CloseHandle(h);
    W>    return 0;
    W>}
    W>


    W>Так вот, когда volatile закомментирован, то рабочий поток не останавливается программа выводит:

    W>

    W>21.3005


    W>А когда volatile есть, поток останавливается и программа выводит:

    W>

    W>0.00287083


    W>Компилятор VC 7.1. Командная строка:

    W>
    W>/O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /FD /EHsc
    W>/MD /GS /Fo"Release/" /Fd"Release/vc70.pdb" /W3 /nologo /c /Wp64 /Zi /TP
    W>
    ... << RSDN@Home 1.1.4 beta 3 rev. 185>>


    SObjectizer: <микро>Агентно-ориентированное программирование на C++.
    Re[7]: volatile у переменной класса
    От: MaximE Великобритания  
    Дата: 18.01.05 09:53
    Оценка:
    Tom wrote:

    > ME>Т.е. ты взял и не читая ляпнул?

    > Не горячись
    >
    > ME>http://www.rsdn.ru/forum/?mid=989456
    Автор: MaximE
    Дата: 16.01.05

    > ME>http://www.rsdn.ru/forum/?mid=988910
    Автор: MaximE
    Дата: 15.01.05

    > ME>http://www.rsdn.ru/forum/?mid=991653
    Автор: MaximE
    Дата: 17.01.05

    >
    > Знавчицца так: Берёшь простенькую программу с обьявленной глобальной volatile и нет переменной. Компилируешь в релизе разными компиляторами. Я проверял на: VC6, VC7.1, gcc 2.95, gcc 3.2, Sun One Studio 5. И смотришь разницу

    Разницу в чем?

    Еще раз, почитай по указанным ссылкам.

    > Ещё раз говорю, что переменная, использующаяся в разных потоках, кроме того, что должна быть защищена приметивами синзхронизации обязана быть volatile.


    Ok, тогда запость, пожалуйста, Александру Терехову ответ на его сообщение http://groups-beta.google.com/group/comp.std.c/msg/ae49dc7a96c625f5 в ньюсгруппу и копию на его e-mail, что ерунду он написал что volatile не нужен для синхронизации в multithreading, а мы тут все вместе почитаем его ответ.

    --
    Maxim Yegorushkin
    Posted via RSDN NNTP Server 1.9
    Re[8]: volatile у переменной класса
    От: Tom Россия http://www.RSDN.ru
    Дата: 18.01.05 10:26
    Оценка:
    ME>Разницу в чем?
    Разницу в генерируемом компилятором коде.

    >> Ещё раз говорю, что переменная, использующаяся в разных потоках, кроме того, что должна быть защищена приметивами синзхронизации обязана быть volatile.


    ME>Ok, тогда запость, пожалуйста, Александру Терехову ответ на его сообщение http://groups-beta.google.com/group/comp.std.c/msg/ae49dc7a96c625f5 в ньюсгруппу и копию на его e-mail, что ерунду он написал что volatile не нужен для синхронизации в multithreading, а мы тут все вместе почитаем его ответ.

    Ты путаешь понятия (или подменяешь). Мы говорим не о том, что volatile необходим только в multithreaded приложениях, а о том что он необходим при использовании переменной несколькими потоками (процессами), но это не отменяет его применимости в других ситуациях.
    Народная мудрось
    всем все никому ничего(с).
    Re[9]: volatile у переменной класса
    От: MaximE Великобритания  
    Дата: 18.01.05 10:31
    Оценка:
    Tom wrote:

    []

    Мы говорим не о том, что volatile необходим только в multithreaded приложениях, а о том что он необходим при использовании переменной несколькими потоками (процессами)...

    Это здесь уже обсудили. Он ни достаточен, ни необходим. Вся информация тебе доступна, читай.

    --
    Maxim Yegorushkin
    Posted via RSDN NNTP Server 1.9
    Re[9]: [2]: : volatile: а можно примеры?
    От: MaximE Великобритания  
    Дата: 18.01.05 10:35
    Оценка:
    AndrewJD wrote:

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

    >
    >>> ME>Мой поинт был в том (если этого до сих пор непонятно уважаемому Шахтеру), что какой бы семантикой не обладал volatile, ее просто не достаточно для multithreading, и поэтому volatile бесполезен для multithreading.
    >>>
    >>> не вдаваясь в технические подробности, из "недостаточно" никак не может следовать "и поэтому ... бесполезен"
    >
    > ME>На этом основании ты хочешь объявить все написанное здесь ересью и провозгласить, что volatile необходим и достаточен для обеспечиния синхронизации при multithreading?
    >
    > volatile — необходимое (в ряде случаев), но не достаточное условие

    http://groups-beta.google.com/group/comp.programming.threads/msg/21878c22d7775997

    Memory barriers must be applied where necessary on many architectures, and
    there is no standard or portable way to generate them. There is no excuse for a
    compiler to require both volatile AND memory barriers, because there's no
    excuse for a compiler to reorder memory access around its own memory barrier
    construct. (Usually either a compiler builtin such as Compaq C/C++ "__MB()" or
    an asm("mb") "pseudocall".) The standard and portable way to ensure memory
    consistency is to rely on the POSIX memory model, which is based solely on
    specific POSIX API calls rather than expensive and inappropriately defined
    language keywords or nonportable hardware instructions. A system or compiler
    that does not provide the proper memory model (without volatile) with proper
    use of the portable POSIX API calls does not conform to POSIX, and cannot be
    considered for serious threading work. Volatile is irrelevant.


    Entirely aside from the language issues, my point was simply that "volatile",
    and especially its association with threaded programming, has been an extremely
    confusing issue for many people. Simply using them together is going to cause
    even more confusion. The illusory promise of volatile will lead novices into
    trouble.


    In contradiction to your absurd statement that "writing multithread programs
    becomes impossible" without volatile, the intended C and C++ semantics
    associated with volatile are neither useful nor sufficient for threaded code.

    And it is WITH volatile, not without, that "the compiler wastes vast
    optimization opportunities", especially as the expense of meeting the volatile
    "contract" is of no benefit to threaded code.


    --
    Maxim Yegorushkin
    Posted via RSDN NNTP Server 1.9
    Re[11]: volatile у переменной класса
    От: eao197 Беларусь http://eao197.blogspot.com
    Дата: 18.01.05 10:59
    Оценка:
    Здравствуйте, Tom, Вы писали:

    Tom>То, что он нидостаточен — это естественно, Но он необходим. Советую не ляпать на клавиатуре, а попробовать самому


    Приведите пример, пожалуйста.
    ... << RSDN@Home 1.1.4 beta 3 rev. 185>>


    SObjectizer: <микро>Агентно-ориентированное программирование на C++.
    Re[11]: volatile у переменной класса
    От: MaximE Великобритания  
    Дата: 18.01.05 11:03
    Оценка:
    Tom wrote:

    > ME>Это здесь уже обсудили. Он ни достаточен, ни необходим. Вся информация тебе доступна, читай.

    > То, что он нидостаточен — это естественно, Но он необходим.

    Приведи конкретный пример.

    --
    Maxim Yegorushkin
    Posted via RSDN NNTP Server 1.9
    Re[5]: volatile у переменной класса
    От: What Беларусь  
    Дата: 18.01.05 11:48
    Оценка:
    Здравствуйте, MaximE, Вы писали:

    ME>Еще раз — volatile абсолютно бесполезен для multithreading.

    На мой взгляд, это слишком категорично. Volatile может быть полезен для multithreading.

    Вы приводили ссылки:
    You do NOT need volatile for threaded programming. You do need it when you share
    data between "main code" and signal handlers, or when sharing hardware registers
    with a device. In certain restricted situations, it MIGHT help when sharing
    unsynchronized data between threads
    (but don't count on it -- the semantics of
    "volatile" are too fuzzy).
    ... << RSDN@Home 1.1.4 beta 3 rev. 185>>
    Re[12]: volatile у переменной класса
    От: Tom Россия http://www.RSDN.ru
    Дата: 18.01.05 12:06
    Оценка:
    ME>Приведи конкретный пример.

    Сырец
    // VolatileTest.cpp : Defines the entry point for the console application.
    //
    
    #include "stdafx.h"
    
    
    // Допустим флаг некоего потока (хотя конечно так лучше не делать)
    //
    int Variable1 = 0;
    
    //
    // Некоя переменная для вычислений. Допустим она используеться
    // одновременно из нескольких потоков.
    //
    int Variable2 = 0;
    
    int Thread()
    {
        while(Variable1 == 0)
        {
            Variable2 += 123;
    
            if (++Variable2 > 6134)
            {
                Variable2 -= 534;
                Variable2 *= Variable2;
            }
            else
            {
                Variable2 -= 32;
                Variable2 += Variable2 / 2;
            }
    
            Sleep(1);
        }
    
        return 0;
    }
    
    void FireFlag()
    {
        Variable1 = 1;
    }
    
    int _tmain(int argc, _TCHAR* argv[])
    {
        //
        // Need to look generated assembler code in the release version
        //
        __asm int 3;
    
        //
        // Assume another thread here
        //
        Thread();
    
        //
        // Signal the Flag
        //
        FireFlag();
    
        return 0;
    }


    Без волатайла
    int Thread()
    {
        while(Variable1 == 0)
    00401000  mov         eax,dword ptr [Variable1 (4072C0h)] 
    00401005  test        eax,eax 
    00401007  jne         Thread+53h (401053h) 
    00401009  push        esi  
    0040100A  mov         esi,dword ptr [__imp__Sleep@4 (405000h)] 
        {
            Variable2 += 123;
    
            if (++Variable2 > 6134)
    00401010  mov         ecx,dword ptr [Variable2 (4072C4h)]  Один раз закешировали и начали использовать уже регистр
    00401016  add         ecx,7Ch 
    00401019  cmp         ecx,17F6h 
    0040101F  jle         Thread+33h (401033h) 
            {
                Variable2 -= 534;
    00401021  sub         ecx,216h 
                Variable2 *= Variable2;
    00401027  mov         eax,ecx 
    00401029  imul        eax,ecx 
    0040102C  mov         dword ptr [Variable2 (4072C4h)],eax  Слили в память только тут
            }
            else
    00401031  jmp         Thread+45h (401045h) 
            {
                Variable2 -= 32;
    00401033  sub         ecx,20h 
                Variable2 += Variable2 / 2;
    00401036  mov         eax,ecx 
    00401038  cdq              
    00401039  sub         eax,edx 
    0040103B  sar         eax,1 
    0040103D  add         ecx,eax 
    0040103F  mov         dword ptr [Variable2 (4072C4h)],ecx  Слили в память только тут
            }
    
            Sleep(1);
    00401045  push        1    
    00401047  call        esi  
    00401049  mov         eax,dword ptr [Variable1 (4072C0h)] 
    0040104E  test        eax,eax 
    00401050  je          Thread+10h (401010h) 
    00401052  pop         esi  
        }
    
        return 0;


    С волатайлом
    int Thread()
    {
        while(Variable1 == 0)
    00401000  mov         eax,dword ptr [Variable1 (4072C0h)] 
    00401005  test        eax,eax 
    00401007  jne         Thread+86h (401086h) 
    00401009  push        esi  
    0040100A  mov         esi,dword ptr [__imp__Sleep@4 (405000h)] 
        {
            Variable2 += 123;
    00401010  mov         eax,dword ptr [Variable2 (4072C4h)] 
    00401015  add         eax,7Bh 
    00401018  mov         dword ptr [Variable2 (4072C4h)],eax
    
            if (++Variable2 > 6134)
    0040101D  mov         ecx,dword ptr [Variable2 (4072C4h)] 
    00401023  inc         ecx  
    00401024  mov         dword ptr [Variable2 (4072C4h)],ecx
    0040102A  cmp         dword ptr [Variable2 (4072C4h)],17F6h
            {
                Variable2 -= 534;
    00401034  mov         edx,dword ptr [Variable2 (4072C4h)] 
    0040103A  jle         Thread+58h (401058h) 
    0040103C  sub         edx,216h 
    00401042  mov         dword ptr [Variable2 (4072C4h)],edx 
                Variable2 *= Variable2;
    00401048  mov         eax,dword ptr [Variable2 (4072C4h)] 
    0040104D  mov         ecx,dword ptr [Variable2 (4072C4h)] 
    00401053  imul        eax,ecx 
            }
            else
    00401056  jmp         Thread+73h (401073h) 
            {
                Variable2 -= 32;
    00401058  sub         edx,20h 
    0040105B  mov         dword ptr [Variable2 (4072C4h)],edx 
                Variable2 += Variable2 / 2;
    00401061  mov         eax,dword ptr [Variable2 (4072C4h)] 
    00401066  mov         ecx,dword ptr [Variable2 (4072C4h)] 
    0040106C  cdq              
    0040106D  sub         eax,edx 
    0040106F  sar         eax,1 
    00401071  add         eax,ecx 
            }
    
            Sleep(1);
    00401073  push        1    
    00401075  mov         dword ptr [Variable2 (4072C4h)],eax 
    0040107A  call        esi  
    0040107C  mov         eax,dword ptr [Variable1 (4072C0h)] 
    00401081  test        eax,eax 
    00401083  je          Thread+10h (401010h) 
    00401085  pop         esi  
        }
    
        return 0;
    00401086  xor         eax,eax 
    }


    Вот и представь, что Thread, испольняется несколькими потоками... Выходит, что потоки узнают о изменениях переменной, только тогда, когда компилятор соизволит слить её в память, а он может этого неделать оочень долго... Почувствуйте разницу
    Народная мудрось
    всем все никому ничего(с).
    Re: volatile у переменной класса
    От: sc Россия  
    Дата: 18.01.05 12:18
    Оценка:
    Здравствуйте, Vet, Вы писали:

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

    Есть, например простой пример:
    volatile int var1 = 1; //ее используют два потока
    ...
    int var2 = var1 = 2;
    var2 = var1;

    Видно, что в результате var2 = 2, но это если не было переключения между потоками ровно после первого присваивания. А если было, то тогда var2 будет иметь новое значение var1. А если не использовать volatile, то второе присваивание будет удалено в результате оптимизации.
    Пример примитивный конечно, в реальной жизни все может быть намного сложнее, и особенно поиск ошибки такого типа.
    Re[6]: volatile у переменной класса
    От: MaximE Великобритания  
    Дата: 18.01.05 12:25
    Оценка:
    Здравствуйте, What, Вы писали:

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


    ME>>Еще раз — volatile абсолютно бесполезен для multithreading.

    W>На мой взгляд, это слишком категорично. Volatile может быть полезен для multithreading.

    W>Вы приводили ссылки:

    W>You do NOT need volatile for threaded programming. You do need it when you share
    W>data between "main code" and signal handlers, or when sharing hardware registers
    W>with a device. In certain restricted situations, it MIGHT help when sharing
    W>unsynchronized data between threads
    (but don't count on it -- the semantics of
    W>"volatile" are too fuzzy).

    Ok, ты работаешь над проектом. Менеджер спрашивает тебя, готов ли ты поставить свою зарплату, что твой многопоточный кусок кода, в котором ты не используешь ф-ций синхронизации, а полагаешься на "fuzzy" семантику volatile, заработает на не Intel SMP системе? Что ты ему ответишь?
    Re[4]: Реальный пример использования volatile
    От: What Беларусь  
    Дата: 18.01.05 12:30
    Оценка:
    Здравствуйте, eao197, Вы писали:

    W>>А зачем здесь синхронизация? Один поток пишет значение переменной, другой читает. Главное, чтобы значение было записано атомарно. Это в данном случае для x86 гарантируется.


    E>Боюсь, что именно из-за таких предположений весь сыр бор вокруг volatile и начался. Я считаю, что есть принципиальные вещи: выделеную память нужно освобождать, открытые файлы закрывать, после входа в критическую секцию нужно выйти оттуда, ..., когда одна нить читает то, что другая может переписать, то это нужно синхронизировать. Это вопрос принципа (с моей точки зрения). И если ему следовать, то:

    E>- мы не зависим от volatile или не volatile;
    E>- мы не зависим от аппаратной платформы (могут быть какие-нибудь специализированные процессоры, на которых извлечение одного байта из памяти может не быть атомарной операцией, а требовать дополнительных арифметических операций/сдвигов);
    E>- мы не зависим от типа данных. Сейчас у нас переменная go -- это bool. Завтра -- это long int, в котором указано, сколько итераций нам еще разрешают сделать. После завтра -- структура, в которой описывается, при каких условиях нужно выходить, а при каких условиях еще можно провести пару-тройку итераций.
    E>А все из-за того, что изначально мы защитились синхронизацией. И не надеялись на особенности конкретной платформы и конткретного компилятора.
    Для того, чтобы не зависеть от платформы, нужно разделять платформенно-зависимый и платформенно-независимый код. А вот платформенно-зависимые примитивы, например, средства синхронизации могут быть реализованы отдельно под некоторые платформы максимально эффективным способом. И если под x86 работа с 32-битными числами атомарна, то в платформенно-зависимых частях кода нужно это использовать.

    W>>С другой стороны, а если бы рабочих потоков было, скажем, 4 вместо 1. И все читали бы одну и ту же переменную. Тогда использование синхронизации могло бы привести к ненужным потерям производительности.

    E>За безопасность в многопоточности нужно платить. Некоторые из-за безопасности на более медленные языки программирования переходят Из-за того, что лишний раз delete вызвать лень
    Да, но зачем платить, когда это не нужно? Например, критические секции, если не надо останавливать поток, обходятся без перехода в режим ядра. Другой пример — паттерн double-checked locking, при реализации которого, кстати, может понадобиться volatile.
    ... << RSDN@Home 1.1.4 beta 3 rev. 185>>
    Re[5]: Реальный пример использования volatile
    От: eao197 Беларусь http://eao197.blogspot.com
    Дата: 18.01.05 12:56
    Оценка:
    Здравствуйте, What, Вы писали:

    E>>А все из-за того, что изначально мы защитились синхронизацией. И не надеялись на особенности конкретной платформы и конткретного компилятора.

    W>Для того, чтобы не зависеть от платформы, нужно разделять платформенно-зависимый и платформенно-независимый код. А вот платформенно-зависимые примитивы, например, средства синхронизации могут быть реализованы отдельно под некоторые платформы максимально эффективным способом. И если под x86 работа с 32-битными числами атомарна, то в платформенно-зависимых частях кода нужно это использовать.

    Так ваша часть была платформо-зависимой! Ok. Тогда volatile была частью этой зависимости.
    Если бы код был POSIX-зависимым, или boost-зависимым, или ACE-зависимым, или commoncpp-зависимым, или glib-зависимым, или Win32-EnterCriticalSection/LeaveCriticalSection-зависимым, то volatile не была бы частью этой зависимости.

    Я это к тому, что вы выбрали мультипоточную модель под конкретную платформу. Причем модель, которую не все считают корректной. И необходимым условием работоспособности этой модели явилось применение volatile. Но вашем конкретном случае эта модель себя оправдывает.

    Спасибо за ваш пример.

    W>>>С другой стороны, а если бы рабочих потоков было, скажем, 4 вместо 1. И все читали бы одну и ту же переменную. Тогда использование синхронизации могло бы привести к ненужным потерям производительности.

    E>>За безопасность в многопоточности нужно платить. Некоторые из-за безопасности на более медленные языки программирования переходят Из-за того, что лишний раз delete вызвать лень
    W>Да, но зачем платить, когда это не нужно? Например, критические секции, если не надо останавливать поток, обходятся без перехода в режим ядра. Другой пример — паттерн double-checked locking, при реализации которого, кстати, может понадобиться volatile.

    Это вы думаете, что платить не нужно. Я считаю, что нужно. Но плату желательно минимизировать. За счет критических секций, хотя бы.
    ... << RSDN@Home 1.1.4 beta 3 rev. 185>>


    SObjectizer: <микро>Агентно-ориентированное программирование на C++.
    Re[4]: Реальный пример использования volatile
    От: AndrewJD США  
    Дата: 18.01.05 13:15
    Оценка:
    Здравствуйте, eao197, Вы писали:

    W>>С другой стороны, а если бы рабочих потоков было, скажем, 4 вместо 1. И все читали бы одну и ту же переменную. Тогда использование синхронизации могло бы привести к ненужным потерям производительности.

    E>За безопасность в многопоточности нужно платить.

    Зачем нужна синхронизация с помощью обьектов ядра, когда один поток пишет атомарное значение и несколько других читает это значение?
    "For every complex problem, there is a solution that is simple, neat,
    and wrong."
    Re[16]: volatile у переменной класса
    От: Tom Россия http://www.RSDN.ru
    Дата: 18.01.05 13:16
    Оценка:
    ME>Твое нежелание читать тред просто потрясает.
    Хватит слов. Код в студию
    Народная мудрось
    всем все никому ничего(с).
    Re[17]: volatile у переменной класса
    От: MaximE Великобритания  
    Дата: 18.01.05 13:21
    Оценка:
    Tom wrote:

    > ME>Твое нежелание читать тред просто потрясает.

    > Хватит слов. Код в студию

    Код чего? Примитивов синхронизации?

    --
    Maxim Yegorushkin
    Posted via RSDN NNTP Server 1.9
    Re[5]: Реальный пример использования volatile
    От: eao197 Беларусь http://eao197.blogspot.com
    Дата: 18.01.05 13:27
    Оценка:
    Здравствуйте, AndrewJD, Вы писали:

    AJD>Зачем нужна синхронизация с помощью обьектов ядра, когда один поток пишет атомарное значение и несколько других читает это значение?


    А в стандарте C++ где нибудь сказано, что вот здесь:
    for (unsigned int i = MaxIter; (i != 0) && go; --i)

    операция чтения переменной go будет атомарной? По-моему, язык C++ этого никак не гарантирует. Даже с помощью volatile.

    А синхронизация нужна хотя бы потому, что чтение общих данных без синхронизации это -- "For every complex problem, there is a solution that is simple, neat, and wrong." (С) AndrewJD

    А если серьезно, то лично я считаю, что лучше переплатить за безопасность синхронизацией, чем потом разгребать проблемы.
    ... << RSDN@Home 1.1.4 beta 3 rev. 185>>


    SObjectizer: <микро>Агентно-ориентированное программирование на C++.
    Re[18]: volatile у переменной класса
    От: Tom Россия http://www.RSDN.ru
    Дата: 18.01.05 14:49
    Оценка:
    ME>Код чего? Примитивов синхронизации?
    Код правильной защиты переменной в multithreaded приложении, без использования volatile
    Народная мудрось
    всем все никому ничего(с).
    Re[6]: Реальный пример использования volatile
    От: AndrewJD США  
    Дата: 18.01.05 15:22
    Оценка:
    Здравствуйте, eao197, Вы писали:
    E>А в стандарте C++ где нибудь сказано, что вот здесь:
    E>
    E>for (unsigned int i = MaxIter; (i != 0) && go; --i)
    E>

    E>операция чтения переменной go будет атомарной? По-моему, язык C++ этого никак не гарантирует. Даже с помощью volatile.

    Атомарность это понятие относится к платформе, а не к языку. volatile — гарантирует, что оптимизатор не будет позволять себе слишком многого.

    E>А синхронизация нужна хотя бы потому, что чтение общих данных без синхронизации это


    Для чего нужна синхронизация если тебе важно знать поменялось значение или нет? Тебе не важно САМО значение, тебе важен факт его изменения. Какая тут нужна синхронизация
    "For every complex problem, there is a solution that is simple, neat,
    and wrong."
    Re[7]: Реальный пример использования volatile
    От: eao197 Беларусь http://eao197.blogspot.com
    Дата: 18.01.05 15:42
    Оценка:
    Здравствуйте, AndrewJD, Вы писали:

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

    E>>А в стандарте C++ где нибудь сказано, что вот здесь:
    E>>
    E>>for (unsigned int i = MaxIter; (i != 0) && go; --i)
    E>>

    E>>операция чтения переменной go будет атомарной? По-моему, язык C++ этого никак не гарантирует. Даже с помощью volatile.

    AJD>Атомарность это понятие относится к платформе, а не к языку. volatile — гарантирует, что оптимизатор не будет позволять себе слишком многого.


    Про то, что может гарантировать volatile в этой ветви, чуть повыше, уже все подробно объяснили. Я не хочу на этом останавливаться.

    Поскольку язык не гарантирует, что чтение переменной go будет атомарным, то мне нужно обеспечить безопасность этого чтения путем синхронизации. Которая относится к платформе, но здесь не используется.

    E>>А синхронизация нужна хотя бы потому, что чтение общих данных без синхронизации это


    AJD>Для чего нужна синхронизация если тебе важно знать поменялось значение или нет? Тебе не важно САМО значение, тебе важен факт его изменения. Какая тут нужна синхронизация

    Ну в данном конткретном случае само значение переменной и указывает на факт его изменения

    А по этому конкретному примеру я уже высказал все, что хотел.
    ... << RSDN@Home 1.1.4 beta 3 rev. 185>>


    SObjectizer: <микро>Агентно-ориентированное программирование на C++.
    Re[6]: Реальный пример использования volatile
    От: What Беларусь  
    Дата: 18.01.05 16:45
    Оценка:
    Здравствуйте, eao197, Вы писали:

    E>Так ваша часть была платформо-зависимой! Ok. Тогда volatile была частью этой зависимости.

    E>Если бы код был POSIX-зависимым, или boost-зависимым, или ACE-зависимым, или commoncpp-зависимым, или glib-зависимым, или Win32-EnterCriticalSection/LeaveCriticalSection-зависимым, то volatile не была бы частью этой зависимости.
    Как сказать... ACE и boost используют volatile в своей реализации.

    E>Я это к тому, что вы выбрали мультипоточную модель под конкретную платформу. Причем модель, которую не все считают корректной. И необходимым условием работоспособности этой модели явилось применение volatile. Но вашем конкретном случае эта модель себя оправдывает.


    E>Спасибо за ваш пример.

    Пожалуйста
    ... << RSDN@Home 1.1.4 beta 3 rev. 185>>
    Re[8]: Реальный пример использования volatile
    От: AndrewJD США  
    Дата: 18.01.05 18:13
    Оценка:
    Здравствуйте, eao197, Вы писали:

    AJD>>Атомарность это понятие относится к платформе, а не к языку. volatile — гарантирует, что оптимизатор не будет позволять себе слишком многого.


    E>Про то, что может гарантировать volatile в этой ветви, чуть повыше, уже все подробно объяснили. Я не хочу на этом останавливаться.


    Так же выше был пример где использовались критические секции для синхронизации. Но оптимизатор на это забил
    "For every complex problem, there is a solution that is simple, neat,
    and wrong."
    Re[15]: volatile у переменной класса
    От: achp  
    Дата: 18.01.05 18:24
    Оценка:
    Здравствуйте, Tom, Вы писали:

    Tom>А ты думаешь компилятор перестанет оптимизировать, если появиться синхронизация?


    Перестанет. Ибо синхронизация немыслима без вызова внешних функций, в отношении которых компилятор бессилен установить, изменяют ли они значение данной переменной.
    Я кончил, джентльмены, мне остается только поблагодарить вас за внимание.
    Re[16]: volatile у переменной класса
    От: achp  
    Дата: 18.01.05 18:24
    Оценка:
    Здравствуйте, emusic, Вы писали:

    E>В этих дискуссиях никто америки не открыл, и большинство компетентных мнений сходится, конечно же, к тому, что ни volatile, ни memory barriers сами по себе проблемы не решают, и в общем случае решают ее лишь в совокупности.


    Хм... Если есть барьер, то зачем volatile?
    Я кончил, джентльмены, мне остается только поблагодарить вас за внимание.
    Re[14]: volatile у переменной класса
    От: emusic Франция https://software.muzychenko.net/ru
    Дата: 18.01.05 19:16
    Оценка:
    Здравствуйте, MaximE, Вы писали:

    ME>Этот код — некорректный многопоточный код, так как он не применяет синхронизацию для доступа к переменной.


    Я тебе приводил корректный код с Critical Sections Он тебе тоже почему-то не понравился
    ... << RSDN@Home 1.1.4 beta 3 rev. 185>>
    Re[16]: volatile у переменной класса
    От: emusic Франция https://software.muzychenko.net/ru
    Дата: 18.01.05 19:16
    Оценка:
    Здравствуйте, achp, Вы писали:

    Tom>>А ты думаешь компилятор перестанет оптимизировать, если появиться синхронизация?


    A>Перестанет. Ибо синхронизация немыслима без вызова внешних функций, в отношении которых компилятор бессилен установить, изменяют ли они значение данной переменной.


    Это верно только для нелокальных переменных. Я уже приводил код с указателями. В каждом потоке в каждый момент времени существует только один указатель на объект, по которому может производиться доступ. Следовательно, допустимо применить оптимизацию работы с указателями, задав компилятору режим No Aliasing.

    Кроме того, если в модуле присутствуют только статические переменные и функции, и указатели на эти статические функции не передаются во внешние функции — компилятор имеет полное право считать, что статические переменные извне изменены быть не могут — за исключением тех, указатели на которые передаются во внешние функции. Пока я не встречал компилятора, который стал бы производить столь глубокий анализ, однако можешь ли ты обосновать некорректность подобного поведения компилятора?
    ... << RSDN@Home 1.1.4 beta 3 rev. 185>>
    Re[6]: volatile у переменной класса
    От: emusic Франция https://software.muzychenko.net/ru
    Дата: 18.01.05 19:31
    Оценка:
    Здравствуйте, What, Вы писали:

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


    W>You do NOT need volatile for threaded programming. You do need it when you share

    W>data between "main code" and signal handlers, or when sharing hardware registers
    W>with a device.

    Мне очень интересно, на что опираются подобные утверждения, кроме голой интуиции Как этот народ технически различает "threaded" и "hardware registers"? Допустим, у меня есть однопроцессорная машина и "device" — плата расширения, втыкаемая в PCI, на которой стоит такой же процессор, что и в системной плате. Я посредством каких-нибудь спецкоманд запускаю выполнение этим "внешним" процессором какой-нибудь части собственного кода. Память — общая, доступ возможен как с моей, так и с той стороны. Это "threaded" или "device"?
    ... << RSDN@Home 1.1.4 beta 3 rev. 185>>
    Re[7]: volatile у переменной класса
    От: emusic Франция https://software.muzychenko.net/ru
    Дата: 18.01.05 19:31
    Оценка:
    Здравствуйте, MaximE, Вы писали:

    ME>Ok, ты работаешь над проектом. Менеджер спрашивает тебя, готов ли ты поставить свою зарплату, что твой многопоточный кусок кода, в котором ты не используешь ф-ций синхронизации, а полагаешься на "fuzzy" семантику volatile, заработает на не Intel SMP системе?


    А ты свою зарплату за то, что код, использующий функции синхронизации, но не использующий volatile, заработает везде, поставишь? Только хорошо подумай перед тем, как согласиться

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

    А в частных случаях, разумеется, можно обойтись как одним volatile, так и одной синхронизацией. Очевидный, в общем-то, вывод.
    ... << RSDN@Home 1.1.4 beta 3 rev. 185>>
    Re[10]: [2]: : volatile: а можно примеры?
    От: Andrew S Россия http://alchemy-lab.com
    Дата: 18.01.05 20:07
    Оценка:
    >> а вот "недостаточно" "и поэтому ... бесполезен" — это действительно ересь хотя бы с точки зрения формальной логики

    ME>Согласен, но с точки зрения треда — это оффтопик.


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

    1. Есть 2 или более потоков.
    2. Есть разделяемая между ними переменная. long.
    3. Запись (и пусть даже чтение) производится при помощи функций InterlockedExchange\InterlockedExchangeAdd или их аналогов.
    4. Мы не привязываемся ни к конкретной архитектуре процессора, ни к конкретному компилятору.

    Возможные варианты (V):

    V1. Переменная объявлена как volatile. Соотв, параметры InterlockedXxx объявлены с volatile.
    V2. Переменная объявлена не как volatile. Соотв, параметры InterlockedXxx без volatile (например, как это было в PSDK 2-х летней давности. Теперь это не так и вынуждает программистов использовать volatile для этих функций. Так что предположения о том, что этого не станут требовать разработчики компиляторов, очевидно, не оправдались).

    Теперь некоторые соображения(A):

    A1. Функции InterlockedXxx могут быть intrinsic (например, http://msdn.microsoft.com/library/en-us/vclang/html/vcrefCompilerIntrinsics.asp)
    A2. Функции InterlockedXxx могут не быть intrinsic.

    Интересуют Ваши (а не ссылки на группо-гугль, где, собственно, ничего нового нет) ответы на следующие вопросы:

    (x) Случай Vx,Ax. Может ли в этом случае компилятор закэшировать значение переменной? Имеются в виду как обычные, так и наиболее агрессивные настройки оптимизации.
    Итого, соотв, 4 варианта.

    PS Мое мнение — volatile в данном аспекте необходимое, но не достаточное условие и должен использоваться для таких разделяемых переменных. По крайней мере, для случая Vx,A1.
    http://www.rusyaz.ru/pr — стараемся писАть по-русски
    Re[8]: volatile у переменной класса
    От: MaximE Великобритания  
    Дата: 18.01.05 20:16
    Оценка:
    emusic wrote:

    > Тебе в который раз повторяют, что для гарантированной работы кода в общем случае обязательны и функции синхронизации, и volatile.


    POSIX не требует volatile. Осталось разобраться для win32. Согласен?

    > Но тебе, похоже, комфортнее делать вид, будто все, как один, сторонники volatile предлагают использовать его вместо функций синхронизации


    По крайней мере, большАя часть их.

    --
    Maxim Yegorushkin
    Posted via RSDN NNTP Server 1.9
    Re[11]: [2]: : volatile: а можно примеры?
    От: MaximE Великобритания  
    Дата: 18.01.05 22:05
    Оценка:
    Andrew S wrote:

    > (x) Случай Vx,Ax. Может ли в этом случае компилятор закэшировать значение переменной? Имеются в виду как обычные, так и наиболее агрессивные настройки оптимизации.

    > Итого, соотв, 4 варианта.

    Не будет закэшировано во всех вариантах. (если, конечно, никто не применит ключ компиляции "компайлер, здесь нет никакого альясинга, мамой клянусь!")

    Если ф-ция внешняя, то компайлер просто не может "видеть" что она делает и ему придется прочитать значения из памяти. В случае с intrinsic — компайлер "знает" эффекты собственного intrinsic.

    --
    Maxim Yegorushkin
    Posted via RSDN NNTP Server 1.9
    Re[6]: [2]: : volatile: а можно примеры?
    От: Шахтер Интернет  
    Дата: 19.01.05 00:20
    Оценка:
    Здравствуйте, eao197, Вы писали:

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


    Ш>>Они уже приведены.


    E>То, что я видел выше нельзя назвать примерами реальных проектов. Это небольшие тестовые программки, которые дополнены комментариями типа "вот когда-нибудь, когда придут крутые-крутые компиляторы, которые увидят, как работают WaitForSingleObject/pthread_mutex_wait, вот тогда...". И еще говорят, что компилятор справедливо опасается оптимизировать доступ к переменным, если перед этим были сделалы какие-то внешние вызовы.


    E>Как мне кажется, довольно характерный пример псевдокода по работе о общими данными в многопоточных приложениях выглядит так:

    E>
    E>// Кто-то, что-то готовит.
    E>lock();
    E>...
    E>flag = ready;
    E>unlock();
    
    E>// Кто-то, что-то ожидает.
    E>while( true )
    E>    lock();
    E>    if( ready != flag )
    E>        unlock();
    E>    else
    E>        ...
    E>        ready = not_ready;
    E>        unlock();
    E>

    E>Причем как раз доступ к общим данным (в данном случае, flag) производиться рядышком с использованием синхронизирующих примитивов.

    E>Из того, что я прочитал, я сделал вывод, что компилятор не будет оптимизировать доступ к общим данным, если рядом есть вызов синхронизирующего примитива (просто потому, что компилятор будет считать этот вызов вызовом с побочными эфектами).


    Не обязательно. Компилятор может иметь список well-known функций, побочные эффекты от которых он знает. Например, фирме Майкрософт ничего не стоит научить VC++ оценивать побочные эффекты от вызова функций из API Win32. Технически, оптимизатор от VC++ содержит всё необходимое для этого.

    E>Компиляторы не делают такой оптимизации сейчас.


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

    Что-то типа.

    CRITICAL_SECTION cs;
    volatile int var1,var2,var3;
    
    {
     ...
     
     EnterCriticalSection(&cs);
    
     locked(var1,var2,var3)
      {
       // var1,var2,var3 здесь перестают рассматриваться как volatile
      }
    
     LeaveCriticalSection(&cs);
    
     ...
    }


    E>И я сомневаюсь, что они будут делать ее в будущем.


    Стандарт это не запрещает. Единственный 100% легальный метод гарантировать это на сегодня -- использовать volatile. Так что всё остальное -- на твой страх и риск.

    E>Хотя бы из-за соображений совместимости.


    Нет никаких сображений совместимости с нелегальным кодом. Полно примеров, когда новые компиляторы отказываются компилировать код, который компилировался старыми компиляторами, но не удовлетворял стандарту.

    E>Поэтому пока я не считаю нужным делать рефакторинг своего кода и вставлять volatile туда, где его не было.


    Пожалуйста. Но ты должен понимать, что делаешь таким образом платформенно-зависимый код.

    E>И я не увидел пока реальных примеров из жизни, которые заставили бы меня это сделать. А было бы полезно увидеть (не только мне), если такие примеры имели место быть.
    ... << RSDN@Home 1.1.0 stable >>
    В XXI век с CCore.
    Копай Нео, копай -- летать научишься. © Matrix. Парадоксы
    Re[6]: [2]: : volatile: а можно примеры?
    От: Шахтер Интернет  
    Дата: 19.01.05 00:20
    Оценка:
    Здравствуйте, MaximE, Вы писали:

    ME>Шахтер wrote:


    ME>[]


    >> E>Предложение: давайте не превращать эту ветвь в очередное выяснение истины. Если есть примеры -- приводите, пожалуйста. Если нет, то будем считать это доказательством правильности позиции Максима

    >>
    >> Они уже приведены.

    ME>Ok, я не прав был в семантике volatile, привел не удачный пример, и прогнал про sequence points.


    ME>Мой поинт был в том (если этого до сих пор непонятно уважаемому Шахтеру), что какой бы семантикой не обладал volatile, ее просто не достаточно для multithreading,


    Я это прекрасно знаю.

    ME>и поэтому volatile бесполезен для multithreading.


    Логическая ошибка. Недостаточно значит, необходимы дополнительные средства. Но это не значит -- не надо использовать.

    ME>--

    ME>Maxim Yegorushkin
    ... << RSDN@Home 1.1.0 stable >>
    В XXI век с CCore.
    Копай Нео, копай -- летать научишься. © Matrix. Парадоксы
    Re[18]: volatile у переменной класса
    От: emusic Франция https://software.muzychenko.net/ru
    Дата: 19.01.05 03:32
    Оценка:
    Здравствуйте, achp, Вы писали:

    E>>Я уже приводил код с указателями. В каждом потоке в каждый момент времени существует только один указатель на объект, по которому может производиться доступ. Следовательно, допустимо применить оптимизацию работы с указателями, задав компилятору режим No Aliasing.


    A>Ну правильно, это же прямой обман компилятора. И вообще это чрезмерно агрессивная оптимизация, в общем случае недопустимая.


    Аргументы, пожалуйста. И просьба прочитать в треде мои аргументы в пользу применения этих ключей оптимизации прежде, чем отвечать.
    ... << RSDN@Home 1.1.4 beta 3 rev. 185>>
    Re[9]: volatile у переменной класса
    От: emusic Франция https://software.muzychenko.net/ru
    Дата: 19.01.05 05:07
    Оценка:
    Здравствуйте, MaximE, Вы писали:

    ME>POSIX не требует volatile.


    Это личные предпочтения POSIX. Не более того. POSIX — замкнутая система, спецификация которой охватывает и аппаратную часть, и саму программу, и окружение программы. Это позволяет ей налагать дополнительные ограничения на поведение компилятора — в частности, на оптимизацию. Однако даже POSIX-совместимый компилятор совершенно не обязан предполагать, что значение любой переменной может измениться после вызова любой внешней функции — к этому его обязывают лишь вызовы известных системных функций.

    ME>Осталось разобраться для win32.


    Кроме POSIX и Win32, в мире не существует больше платформ? В этом твоя главная ошибка — ты высказываешь общие утверждения, опираясь лишь на частные случаи. О том, что в POSIX достаточно барьеров, с тобой никто не спорил — это установлено спецификацией POSIX. Однако нет всеобщей спецификации, которая гарантировала бы достаточность разного рода средств синхронизации в отсутствие volatile.
    ... << RSDN@Home 1.1.4 beta 3 rev. 185>>
    Re[7]: [2]: : volatile: а можно примеры?
    От: MaximE Великобритания  
    Дата: 19.01.05 06:06
    Оценка:
    Здравствуйте, Шахтер, Вы писали:

    []

    ME>>Мой поинт был в том (если этого до сих пор непонятно уважаемому Шахтеру), что какой бы семантикой не обладал volatile, ее просто не достаточно для multithreading,


    Ш>Я это прекрасно знаю.


    ME>>и поэтому volatile бесполезен для multithreading.


    Ш>Логическая ошибка. Недостаточно значит, необходимы дополнительные средства. Но это не значит -- не надо использовать.


    Исправляю свою логическую ошибку — volotile не недостаточен, а иррелевантен.
    Re[10]: volatile у переменной класса
    От: MaximE Великобритания  
    Дата: 19.01.05 06:20
    Оценка:
    Здравствуйте, emusic, Вы писали:

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


    ME>>POSIX не требует volatile.


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


    Правилнее было бы сказать, что win32 — это закрытая система. POSIX — открытая, можешь разработать и внести свои предложения на рассмотрение. (например потребовать, чтоб volatile был нужен )

    E>Однако даже POSIX-совместимый компилятор совершенно не обязан предполагать, что значение любой переменной может измениться после вызова любой внешней функции


    Это так.

    E> — к этому его обязывают лишь вызовы известных системных функций.


    POSIX явно специфицирует какие функции являются барьерами.

    ME>>Осталось разобраться для win32.


    E>Кроме POSIX и Win32, в мире не существует больше платформ?


    Я говорю про то, что я знаю. На мой взгляд, POSIX и win32 — самые распространенные. Если ты специалист в mac, dec или еще каких threads, можешь просветить.

    E>В этом твоя главная ошибка — ты высказываешь общие утверждения, опираясь лишь на частные случаи. О том, что в POSIX достаточно барьеров, с тобой никто не спорил — это установлено спецификацией POSIX.


    Для меня POSIX и win32 — это 100% случаев. Хочешь обсудить другие платформы — тебе никто не запрещает.

    E>Однако нет всеобщей спецификации, которая гарантировала бы достаточность разного рода средств синхронизации в отсутствие volatile.


    Еще раз: POSIX volatile не нужен. В MSDN я также не нашел упоминания, что им нужен volatile. Делаю вывод, что для win32 он также не нужен.
    Re[11]: volatile у переменной класса
    От: Odi$$ey Россия http://malgarr.blogspot.com/
    Дата: 19.01.05 06:34
    Оценка:
    Здравствуйте, MaximE, Вы писали:

    ME>В MSDN я также не нашел упоминания, что им нужен volatile. Делаю вывод, что для win32 он также не нужен.


    Re: volatile у переменной класса
    Автор: c-smile
    Дата: 10.01.05
    Re[12]: volatile у переменной класса
    От: MaximE Великобритания  
    Дата: 19.01.05 08:11
    Оценка:
    Здравствуйте, Odi$$ey, Вы писали:

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


    ME>>В MSDN я также не нашел упоминания, что им нужен volatile. Делаю вывод, что для win32 он также не нужен.


    OE>Re: volatile у переменной класса
    Автор: c-smile
    Дата: 10.01.05


    Это единственное упоминание volatile и multithreading в MSDN. (там еще есть куски threaded кода с volatile).

    Первое, цитита относится к секции MSDN C/C++ Languages, где MS ошибочно пытается своими словами трактовать стандарт вообще, и ключевое слово volatile в частности.

    Второе, нигде в секции MSDN DLLs, Processes and Threads не упоминается о том, что shared variables должны быть volatile. Из этого следует, что это не является необходимым для win32 threading model. Логично также предположить, что если бы это действительно было необходимым, об этом было бы явно там написано (тем более что это официальная док-ция).
    Re[7]: Реальный пример использования volatile
    От: eao197 Беларусь http://eao197.blogspot.com
    Дата: 19.01.05 08:42
    Оценка:
    Здравствуйте, What, Вы писали:

    E>>Если бы код был POSIX-зависимым, или boost-зависимым, или ACE-зависимым, или commoncpp-зависимым, или glib-зависимым, или Win32-EnterCriticalSection/LeaveCriticalSection-зависимым, то volatile не была бы частью этой зависимости.

    W>Как сказать... ACE и boost используют volatile в своей реализации.

    Они в своей реализации могут использовать все, что им понравиться, лишь бы работало. Но они не требуют, чтобы мои данные были volatile
    ... << RSDN@Home 1.1.4 beta 3 rev. 185>>


    SObjectizer: <микро>Агентно-ориентированное программирование на C++.
    Re[12]: volatile у переменной класса
    От: MaximE Великобритания  
    Дата: 19.01.05 09:01
    Оценка:
    emusic wrote:

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

    >
    > E>>POSIX — замкнутая система, спецификация которой охватывает и аппаратную часть, и саму программу, и окружение программы.
    >
    > ME>Правилнее было бы сказать, что win32 — это закрытая система. POSIX — открытая, можешь разработать и внести свои предложения на рассмотрение.
    >
    > POSIX — не закрытая, а замкнутая система. Это означает, что спецификация платформы, кроме аппаратных особенностей и программной среды, включает еще и требования к языку, в данном случае — C/C++. Чтобы соответствовать спецификации POSIX, компилятор обязан обеспечить условия взаимной видимости переменных в pthreads. Однако это вовсе не обязывает его обеспечивать их в случае организации параллелизма иными, нежели pthreads, способами. Намек понятен?

    Компилятор должен поддерживать многопоточность — это раз. Семантика volatile — implementation defined — это два.

    Никакой стандарт не гарантирует, что volatile вставит load инструкцию, но док-ции к (некоторым) компиляторам это гарантируют (чти и есть implementation defined). Но это еще пол дела.

    Во-первых, load инструкция, в-общем, не гарантирует загрузку актуального значения из памяти без использование барьеров памяти. Во-вторых, платформа должна поддерживать атомарную загрузку/сохранение переменной, помеченной как volatile, также эта переменная должна быть выровнена в соответствии с требованиями той атомарной инструкции, иначе из-за явления word tearing вся атомарность инструкции сойдет на нет.

    Есть тип, который гарантирует атомарность load и store на конкретной платформы для переменной этого типа — это sig_atomic_t. Только, почему-то, нет типа thread_atomic_t.

    > ME>Я говорю про то, что я знаю.

    >
    > Нет, изначально ты высказывал именно всеобщие утверждения о "бесполезности и даже вредности" volatile. И лишь после того, как тебя приперли к стенке, ты начал ссылаться на POSIX — опять-таки распространяя эту частную (пусть и популярную) систему на все случаи жизни.

    И сейчас утверждаю, что volatile бесполезен и вреден для multithreading.

    Одно из применений multithreading — получить максимальное быстродействие, задействовав все процессоры системы. С другой стороны, volatile variables связывают руки оптимизатору. Звучит глупо: хочешь добиться максимального быстродействия, но запрещаешь оптимизацию.

    Компилятор, который бы требовал применение volatile к thread shared variables для конкретной платформы по этой причине попросту бы там не продавался. В опровержение моих слов назови хоть один такой компилятор.

    > ME> На мой взгляд, POSIX и win32 — самые распространенные. Если ты специалист в mac, dec или еще каких threads, можешь просветить.

    >
    > Да дело же не в конкретных платформах и не в конкретных же реализациях многопоточности. А в том, что, если мы хотим обеспечить максимальную переносимость кода — мы обязаны изначально снабдить каждую разделямую переменную спецификатором volatile ...

    Это твои выдумки. Приведи пункт стандарта или соответсвующий текст из reference manual к какой либо threading model (кроме java, конечно, где volatile имеет совсем другую семантику).

    []


    > ME>Для меня POSIX и win32 — это 100% случаев.

    >
    > Это для тебя. Для кого-то, кроме BC 3.1 for DOS, ничего другого не существует Если уж на то пошло, то в оригинальном сообщении автор спрашивал, "есть ли необходимость делать разделяемую переменную volatile", а не "достаточно ли будет одного volatile" для нормальной работы. И ссылался при этом на Рихтера, из чего можно было сделать вывод, что он работает под Win32. А ты ему с места в карьер принялся доказывать "бесполезность и вредность" volatile, да еще и со ссылками на POSIX впоследствии

    Если бы он завтра это еще раз написал, я бы ему еще раз так и ответил.

    > ME>Еще раз: POSIX volatile не нужен. В MSDN я также не нашел упоминания, что им нужен volatile.

    >
    > То есть, тебе требуется именно явное указание на его нужность? Оговорки насчет "concurrently executing thread" в описании самого спецификатора volatile тебе недостаточно? Мда, тяжелый случай.

    Эта оговорка, а лучше сказать ошибка, сидит в секции C/C++ Language Reference с незапамятных времен. Как умеют люди из mictrosoft трактовать C++ стандарт и писать код на C++ мы все тут знаем.

    Скачай Platform SDK, и найди в его документации упоминание о том, что thread shared variables должны быть volatile.

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

    ME>Это единственное упоминание volatile и multithreading в MSDN.


    Нет, это единственное упоминание, найденное тобой Ибо авторы MSDN не предполагали, что ты станешь искать непременно по слову multithreading. Поищи по thread или concurrent.

    Еще про volatile есть статейка 324866 (a variable in the kernel that is used to manage the list of pending-event notifications was not declared as volatile).

    Кстати, в VC++ 7 появилась intrinsic-функция _ReadWriteBarrier. Это как раз случай барьера на уровне компилятора — в отличие от барьера на уровне аппаратуры.

    ME>Второе, нигде в секции MSDN DLLs, Processes and Threads не упоминается о том, что shared variables должны быть volatile.


    Опять-таки — с чего ты взял, что об этом должно упоминаться непременно в указанной секции? Если тебе удобно там это искать — MSDN-то при чем? А о том, что volatile может потребоваться для разделяемых данных, раз десять упомянуто в секциях описания языка, где идет речь об определениях переменных, квалификаторах, указателях и т.п. По-моему, вполне резонно предполагать, что перед изучением Win API программист хотя бы в общих чертах ознакомится с языком вообще.

    Еще к VC++ 2.0 была статейка 120926:
    If the value of a variable can be modified by another thread or by the operating system and your program depends on this behavior, you should declare the variable as volatile. Without the volatile keyword, the optimizing compiler may enregister a copy of this variable, leading to unexpected behavior.

    ME> Из этого следует, что это не является необходимым для win32 threading model.


    Если бы секция "DLLs, processes and threads" являлась исчерпывающей документацией по программированию многопоточных приложений на C/C++ под Win32 — тогда следовало бы.

    ME> Логично также предположить, что если бы это действительно было необходимым, об этом было бы явно там написано (тем более что это официальная док-ция).


    Оно явно и написано. Во многих местах, на разные лады. Если кому-то угодно читать лишь выборочно — это его личные трудности
    ... << RSDN@Home 1.1.4 beta 3 rev. 185>>
    Re[14]: volatile у переменной класса
    От: MaximE Великобритания  
    Дата: 19.01.05 12:41
    Оценка:
    emusic wrote:

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

    >
    > ME>Это единственное упоминание volatile и multithreading в MSDN.
    >
    > Нет, это единственное упоминание, найденное тобой Ибо авторы MSDN не предполагали, что ты станешь искать непременно по слову multithreading. Поищи по thread или concurrent.

    Я искал — безрезультатно.

    > Еще про volatile есть статейка 324866 (a variable in the kernel that is used to manage the list of pending-event notifications was not declared as volatile).


    Правильная статейка. volatile для этого и предназначен — для переменных изменяемых обработчиками сигналов и прерываний.

    Хотя статья не имеет никакого отношения к multithreading.

    > Кстати, в VC++ 7 появилась intrinsic-функция _ReadWriteBarrier. Это как раз случай барьера на уровне компилятора — в отличие от барьера на уровне аппаратуры.


    Что это подтверждает или опровергает в контексте данной ветки?

    > ME>Второе, нигде в секции MSDN DLLs, Processes and Threads не упоминается о том, что shared variables должны быть volatile.

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

    Только в C/C++ Language Reference, C/C++ Language and C++ Libraries, Visual C++ Programmer's Guide — copy'n'paste. Все.

    > По-моему, вполне резонно предполагать, что перед изучением Win API программист хотя бы в общих чертах ознакомится с языком вообще.


    ... Ознакомится и удивится, почему они приплели туда multithreading.

    > Еще к VC++ 2.0 была статейка 120926:

    > If the value of a variable can be modified by another thread or by the operating system and your program depends on this behavior, you should declare the variable as volatile. Without the volatile keyword, the optimizing compiler may enregister a copy of this variable, leading to unexpected behavior.

    Они забыли дописать "or use syncronization functions".

    > ME> Из этого следует, что это не является необходимым для win32 threading model.

    >
    > Если бы секция "DLLs, processes and threads" являлась исчерпывающей документацией по программированию многопоточных приложений на C/C++ под Win32 — тогда следовало бы.

    Логично предположить, что вся необходимая документация к API содержится в его reference. В Process and Thread Reference нет ни требований, ни рекоммендаций делать переменные volatile.

    > Оно явно и написано. Во многих местах, на разные лады. Если кому-то угодно читать лишь выборочно — это его личные трудности


    Приведи конкретные ссылки, в которых сказано, что переменные, разделяемые потоками, помимо использования синхронизации должны быть volatile.

    --
    Maxim Yegorushkin
    Posted via RSDN NNTP Server 1.9
    Re: ужас
    От: Seriously Serious  
    Дата: 19.01.05 20:09
    Оценка:
    От этого всего у меня вопросы:
    1) Гарантируется ли что-нибудь относительно порядка вызова функций синхронизации? или компилятор тут тоже может оптимизировать как захочет?
    2) Имеет ли право компилятор все переменные держать в регистрах? (где об этом в стандарте сказано?)
    Re[2]: ужас
    От: MaximE Великобритания  
    Дата: 19.01.05 22:55
    Оценка:
    Здравствуйте, Seriously Serious, Вы писали:

    SS>От этого всего у меня вопросы:

    SS>1) Гарантируется ли что-нибудь относительно порядка вызова функций синхронизации? или компилятор тут тоже может оптимизировать как захочет?

    Гарантируется. После вызова "непрозрачной" ф-ции компилятор будет перечитывать значения всех переменных из памяти. В противном случае даже single threaded код работать не будет.

    У компилятора просто нет никакой возможности установить, что изменяет "непрозрачная" ф-ция. К примеру, C++ runtime может сохранить адреса всех глобальных переменных и любая "непрозрачная" ф-ция может изменить значение какой либо глобальной переменной не принимая ее адреса явно в качестве параметра вызова. Компилятору знание об эффектах "непрозрачных функций" недоступно, поэтому ему придется перечитывать все переменные из памяти.

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

    SS>2) Имеет ли право компилятор все переменные держать в регистрах? (где об этом в стандарте сказано?)


    Имеет, но см. п.1.
    Re[19]: volatile у переменной класса
    От: c-smile Канада http://terrainformatica.com
    Дата: 20.01.05 00:45
    Оценка:
    Здравствуйте, achp, Вы писали:

    A>Прохождение барьера всегда связано с вызовом внешней функции. Объект, к которому возможно обращение из нескольких потоков — либо глобальный, либо к нему ранее были созданы пути доступа, которые компилятор отследить не в силах. Следовательно, компилятор обязан предполагать возможность изменения данных объектов.


    Как выглядит "барьер" в стандарте C++?
    Re[19]: volatile у переменной класса
    От: c-smile Канада http://terrainformatica.com
    Дата: 20.01.05 00:51
    Оценка:
    Здравствуйте, achp, Вы писали:

    A>Причем здесь это? Прохождение барьера всегда связано с вызовом внешней функции. Объект, к которому возможно обращение из нескольких потоков — либо глобальный, либо к нему ранее были созданы пути доступа, которые компилятор отследить не в силах. Следовательно, компилятор обязан предполагать возможность изменения данных объектов.


    Что такое "внешняя" функция?
    Для компилятора и линкера все функции "внутренние" так как сидят в соотв. lib файлах.
    Re[3]: ужас
    От: Шахтер Интернет  
    Дата: 20.01.05 01:49
    Оценка:
    Здравствуйте, MaximE, Вы писали:

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


    SS>>От этого всего у меня вопросы:

    SS>>1) Гарантируется ли что-нибудь относительно порядка вызова функций синхронизации? или компилятор тут тоже может оптимизировать как захочет?

    ME>Гарантируется. После вызова "непрозрачной" ф-ции компилятор будет перечитывать значения всех переменных из памяти. В противном случае даже single threaded код работать не будет.


    ME>У компилятора просто нет никакой возможности установить, что изменяет "непрозрачная" ф-ция. К примеру, C++ runtime может сохранить адреса всех глобальных переменных и любая "непрозрачная" ф-ция может изменить значение какой либо глобальной переменной не принимая ее адреса явно в качестве параметра вызова. Компилятору знание об эффектах "непрозрачных функций" недоступно, поэтому ему придется перечитывать все переменные из памяти.


    ME>Ok, компилятору, обычно, известны эффекты всех ф-ций, которые выполняет его же C++ runtime, но это был лишь пример, и вместо C++ runtime может выступать любой C/C++ API, к исходникам которого у компилятора нет доступа.


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

    SS>>2) Имеет ли право компилятор все переменные держать в регистрах? (где об этом в стандарте сказано?)


    ME>Имеет, но см. п.1.
    ... << RSDN@Home 1.1.0 stable >>
    В XXI век с CCore.
    Копай Нео, копай -- летать научишься. © Matrix. Парадоксы
    Re[11]: volatile у переменной класса
    От: Шахтер Интернет  
    Дата: 20.01.05 01:49
    Оценка:
    Здравствуйте, MaximE, Вы писали:

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


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


    ME>>>POSIX не требует volatile.


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


    ME>Правилнее было бы сказать, что win32 — это закрытая система. POSIX — открытая, можешь разработать и внести свои предложения на рассмотрение. (например потребовать, чтоб volatile был нужен )


    E>>Однако даже POSIX-совместимый компилятор совершенно не обязан предполагать, что значение любой переменной может измениться после вызова любой внешней функции


    ME>Это так.


    E>> — к этому его обязывают лишь вызовы известных системных функций.


    ME>POSIX явно специфицирует какие функции являются барьерами.


    ME>>>Осталось разобраться для win32.


    E>>Кроме POSIX и Win32, в мире не существует больше платформ?


    ME>Я говорю про то, что я знаю. На мой взгляд, POSIX и win32 — самые распространенные. Если ты специалист в mac, dec или еще каких threads, можешь просветить.


    E>>В этом твоя главная ошибка — ты высказываешь общие утверждения, опираясь лишь на частные случаи. О том, что в POSIX достаточно барьеров, с тобой никто не спорил — это установлено спецификацией POSIX.


    ME>Для меня POSIX и win32 — это 100% случаев.


    А для меня -- нет. Есть ещё vxWorks, например.

    ME>Хочешь обсудить другие платформы — тебе никто не запрещает.


    E>>Однако нет всеобщей спецификации, которая гарантировала бы достаточность разного рода средств синхронизации в отсутствие volatile.


    ME>Еще раз: POSIX volatile не нужен. В MSDN я также не нашел упоминания, что им нужен volatile. Делаю вывод, что для win32 он также не нужен.


    Странный вывод. Win32 не налагает ограничений на компилятор, так что гарантий, что какой-нибудь gcc не захочет слишком хорошо соптимизировать нет никаких. Более того, даже родной Майкрософтовский VC++ может выдать гадость, поскольку Майкрософт компания большая, а в таких компаниях левая рука часто не знает, что делает правая.
    ... << RSDN@Home 1.1.0 stable >>
    В XXI век с CCore.
    Копай Нео, копай -- летать научишься. © Matrix. Парадоксы
    Поведение C++ runtime
    От: emusic Франция https://software.muzychenko.net/ru
    Дата: 20.01.05 04:04
    Оценка:
    Здравствуйте, MaximE, Вы писали:

    ME>К примеру, C++ runtime может сохранить адреса всех глобальных переменных и любая "непрозрачная" ф-ция может изменить значение какой либо глобальной переменной не принимая ее адреса явно в качестве параметра вызова.


    Охренеть. А что еще может сделать C++ runtime столь же неявно? Из того, что в описаниях библиотечных функций не оговорено, что эти функции не изменяют значений "левых" переменных, делаем вывод, что перед вызовом каждой функции нам нужно сохранять в файле значения всех глобальных переменных, а после возврата — восстанавливать? Стековый кадр, надеюсь, C++ runtime без спроса корежить не станет?
    ... << RSDN@Home 1.1.4 beta 3 rev. 185>>
    Re[8]: [2]: : volatile: а можно примеры?
    От: c-smile Канада http://terrainformatica.com
    Дата: 20.01.05 06:05
    Оценка:
    Здравствуйте, eao197, Вы писали:

    E>Ничего личного, Шахтер, но я более склонен согласиться с Мейерсом, чем с вами


    Советую внимательно глянуть на код с volatile.
    Там продемонстрировано то что volatile не решает отдельную конкретную и нетривиальну проблему.

    Но нигде Майерс не говорит о том что volatile не решает базовую проблему "указание компилятору на то что данная переменная можеть изменить значение вне normal flow программы".
    Re[2]: volatile у переменной класса
    От: Mr. None Россия http://mrnone.blogspot.com
    Дата: 20.01.05 06:27
    Оценка:
    Здравствуйте, MaximE, Вы писали:

    ME>Vet wrote:


    ME>volatile не имеет никакого отношения к multithreading, поэтому его применение в этой ситуации не только бесполезно, но может быть и вредно, так как с volatile компилятор не сможет соптимизировтать доступ к этой переменной. Но если один из потоков изменяет переменную, синхронизация при помощи мютексов обязательна.


    Так надоело по крупицам вылавливать информацию о volatile и multithreading`ге и некоторых других особенностях плюсов, связанных с этим... Максим, если у вас богатый опыт в этом вопросе, может наконец-то статью напишете, где изложите все свои знания насчёт этих вопросов? Интересно было бы почитать...
    Компьютер сделает всё, что вы ему скажете, но это может сильно отличаться от того, что вы имели в виду.
    Re: Поведение C++ runtime
    От: eao197 Беларусь http://eao197.blogspot.com
    Дата: 20.01.05 07:41
    Оценка:
    Здравствуйте, emusic, Вы писали:

    E>Охренеть. А что еще может сделать C++ runtime столь же неявно? Из того, что в описаниях библиотечных функций не оговорено, что эти функции не изменяют значений "левых" переменных, делаем вывод, что перед вызовом каждой функции нам нужно сохранять в файле значения всех глобальных переменных, а после возврата — восстанавливать? Стековый кадр, надеюсь, C++ runtime без спроса корежить не станет?


    Шутки-шутками, но допустим, я захотел, чтобы моя программа использовала мою функцию strlen. Я не описываю ее прототипа, т.к. он определен в <cstring>, просто прилинковываю к программе еще один obj или lib. Но задачей моей strlen, кроме основной работы, может быть, скажем сбор статистики. Или strlen помещает последнюю вычесленную длину в глобальную переменную, чтобы она была доступна без повторного обращения к strlen. Или кэширует адреса строк и их длины для того, чтобы повторно не вычислять длину той же самой строки. Для этого моя strlen модифицирует какие-либо глобальные данные. Которые могут быть определены даже в другой lib-е. Так вот мне интересно, имеет ли право компилятор, встретив где-то в коде strlen посчитать, что он все знает про эту функцию (она же из стандартной библиотеки) и оптимизировать все, что находится вокруг нее? Причем меня волнует компилятор, который, пока, делает основную оптимизацию, а не линкер, который-то явно будет знать, что strlen не стандартная.

    Пример с strlen может быть и притянут с потолка. Но почему такого не может быть с malloc/free/realloc? Ведь предоставление своих версий глобальных new и delete является распространенной практикой.
    ... << RSDN@Home 1.1.4 beta 3 rev. 185>>


    SObjectizer: <микро>Агентно-ориентированное программирование на C++.
    Re[9]: [2]: : volatile: а можно примеры?
    От: eao197 Беларусь http://eao197.blogspot.com
    Дата: 20.01.05 07:55
    Оценка:
    Здравствуйте, c-smile, Вы писали:

    CS>Советую внимательно глянуть на код с volatile.

    CS>Там продемонстрировано то что volatile не решает отдельную конкретную и нетривиальну проблему.

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

    CS>Но нигде Майерс не говорит о том что volatile не решает базовую проблему "указание компилятору на то что данная переменная можеть изменить значение вне normal flow программы".


    А с этим я никогда и не спорил. Поэтому еще раз проясню свою позицию: я хочу увидеть реальные примеры (из реальных, а не тестовых примеров), когда использовались примитивы синхронизации, но приложение все равно работало не правильно до тех пор, пока не было использовано volatile. При этом меня не интересуют ни обработчики аппаратных прерываний, ни работа с железом через отображаемые в память порты ввода/вывода.

    Прошу не приводить примеров, когда компилятору специальными ключами явно указывали, что ни одна функция не имеет побочных эффектов. Применение такого ключа в многопоточной программе, ИМХО, является проявлением излишнего оптимизма программиста. Кроме того, такой пример я уже видел. Может есть что-то еще?
    ... << RSDN@Home 1.1.4 beta 3 rev. 185>>


    SObjectizer: <микро>Агентно-ориентированное программирование на C++.
    Re[4]: volatile у переменной класса
    От: MaximE Великобритания  
    Дата: 20.01.05 08:56
    Оценка:
    Здравствуйте, emusic, Вы писали:

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


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


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


    И можно также взглянуть на эту структуру:
    // winnt.h
    
    typedef struct _RTL_CRITICAL_SECTION {
        PRTL_CRITICAL_SECTION_DEBUG DebugInfo;
    
        //
        //  The following three fields control entering and exiting the critical
        //  section for the resource
        //
    
        LONG LockCount;
        LONG RecursionCount;
        HANDLE OwningThread;        // from the thread's ClientId->UniqueThread
        HANDLE LockSemaphore;
        ULONG_PTR SpinCount;        // force size on 64-bit systems when packed
    } RTL_CRITICAL_SECTION, *PRTL_CRITICAL_SECTION;


    Каунтеры не объявлены как volatile.

    Конечно, защитников volatile это не убедит, т.к. они скажут, что в ms знали особенности компилятора и нужные ключи компиляции, когда они компилировали ф-ции EnterCriticalSection et al.
    Re[3]: ужас
    От: Tom Россия http://www.RSDN.ru
    Дата: 20.01.05 09:19
    Оценка:
    Здравствуйте, MaximE, Вы писали:

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


    SS>>От этого всего у меня вопросы:

    SS>>1) Гарантируется ли что-нибудь относительно порядка вызова функций синхронизации? или компилятор тут тоже может оптимизировать как захочет?

    ME>Гарантируется. После вызова "непрозрачной" ф-ции компилятор будет перечитывать значения всех переменных из памяти. В противном случае даже single threaded код работать не будет.


    Что такое "непрозрачные" функции, где о них упоминание в стандарте и кем карантируется то, что ты сказал?
    Народная мудрось
    всем все никому ничего(с).
    Re[5]: volatile у переменной класса
    От: Andrew S Россия http://alchemy-lab.com
    Дата: 20.01.05 09:58
    Оценка:
    E>>Надо отдать должное реализации этих функций: если секция не захвачена другим потоком — объекты синхронизации не задействуются, все выливается только в вызовы InterlockedXXX.

    ME>И можно также взглянуть на эту структуру:


    ME>Каунтеры не объявлены как volatile.


    ME>Конечно, защитников volatile это не убедит, т.к. они скажут, что в ms знали особенности компилятора и нужные ключи компиляции, когда они компилировали ф-ции EnterCriticalSection et al.


    А что на нее глядеть? Она пользуется извне только для отладочных целей (соотв, когда никакой оптимизации и нет). Или вы думаете, что при компиляции kernel32.dll они пользуются winnt.dll из своего PSDK?
    PS Вообще, знание структуры CS совсем не обязательно для ее нормального использования, точнее, оно вообще не нужно.
    http://www.rusyaz.ru/pr — стараемся писАть по-русски
    Re[3]: ужас
    От: Seriously Serious  
    Дата: 20.01.05 10:06
    Оценка:
    А если ВСЕ функции станут прозрачными и компилятор будет ВСЁ держать в регистрах?
    Re[20]: volatile у переменной класса
    От: achp  
    Дата: 20.01.05 10:15
    Оценка:
    Здравствуйте, c-smile, Вы писали:

    CS>Как выглядит "барьер" в стандарте C++?


    Барьер в стандарте Си/Си++ отсутствует. Отсюда следует, что единственный способ, которым он может быть выражен — вызов некоторой функции.
    Я кончил, джентльмены, мне остается только поблагодарить вас за внимание.
    Re[20]: volatile у переменной класса
    От: achp  
    Дата: 20.01.05 10:15
    Оценка:
    Здравствуйте, c-smile, Вы писали:

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


    A>>Причем здесь это? Прохождение барьера всегда связано с вызовом внешней функции. Объект, к которому возможно обращение из нескольких потоков — либо глобальный, либо к нему ранее были созданы пути доступа, которые компилятор отследить не в силах. Следовательно, компилятор обязан предполагать возможность изменения данных объектов.


    CS>Что такое "внешняя" функция?

    CS>Для компилятора и линкера все функции "внутренние" так как сидят в соотв. lib файлах.

    Внешняя в данном контексте значит "внешняя по отношению к данной единице комипляции" или иначе "определённая где-то за пределами данной единицы компиляции".

    Кстати, конкретный вопрос. Назовите тот библиотечный файл, в котором "сидит" тело функции WaitForSingleObject.
    Я кончил, джентльмены, мне остается только поблагодарить вас за внимание.
    Re[3]: ужас
    От: achp  
    Дата: 20.01.05 10:34
    Оценка:
    Здравствуйте, MaximE, Вы писали:

    ME>Гарантируется. После вызова "непрозрачной" ф-ции компилятор будет перечитывать значения всех переменных из памяти. В противном случае даже single threaded код работать не будет.


    Ну, положим, не совсем всех. Если это локальная переменная, адрес которой нигде "налево" не "утекал", то её вполне можно заховать и в регистре.
    Я кончил, джентльмены, мне остается только поблагодарить вас за внимание.
    Re[4]: ужас
    От: achp  
    Дата: 20.01.05 10:34
    Оценка:
    Здравствуйте, Seriously Serious, Вы писали:

    SS>А если ВСЕ функции станут прозрачными и компилятор будет ВСЁ держать в регистрах?


    Во-первых, из "прозрачности" ещё не следует, что можно "всё держать в регистрах". "Прозрачность", то есть доступность для компилятора тела данной функции, может позволить компилятору сделать вывод о том, какие объекты подвергаются модификации при её вызове, а какие — нет. А может и не позволить.

    Во-вторых, тогда барьеры (и многопоточность вообще) станут просто невозможны.
    Я кончил, джентльмены, мне остается только поблагодарить вас за внимание.
    Re[3]: volatile у переменной класса
    От: MaximE Великобритания  
    Дата: 20.01.05 10:50
    Оценка:
    Mr. None wrote:

    > ME>volatile не имеет никакого отношения к multithreading, поэтому его применение в этой ситуации не только бесполезно, но может быть и вредно, так как с volatile компилятор не сможет соптимизировтать доступ к этой переменной. Но если один из потоков изменяет переменную, синхронизация при помощи мютексов обязательна.

    >
    > Так надоело по крупицам вылавливать информацию о volatile и multithreading`ге и некоторых других особенностях плюсов, связанных с этим... Максим, если у вас богатый опыт в этом вопросе, может наконец-то статью напишете, где изложите все свои знания насчёт этих вопросов? Интересно было бы почитать...

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

    Чему могу научить — так это пользоваться google'ом для поиска информации.

    --
    Maxim Yegorushkin
    Posted via RSDN NNTP Server 1.9
    Re[7]: [2]: : volatile: а можно примеры?
    От: achp  
    Дата: 20.01.05 11:01
    Оценка:
    Здравствуйте, Шахтер, Вы писали:

    Ш>
    Ш>CRITICAL_SECTION cs;
    Ш>volatile int var1,var2,var3;
    
    Ш>{
    Ш> ...
     
    Ш> EnterCriticalSection(&cs);
    
    Ш> locked(var1,var2,var3)
    Ш>  {
    Ш>   // var1,var2,var3 здесь перестают рассматриваться как volatile
    Ш>  }
    
    Ш> LeaveCriticalSection(&cs);
    
    Ш> ...
    Ш>}
    Ш>


    Я бы предпочёл код такого вида:

    CRITICAL_SECTION cs;
    int sealed var1, var2, var3; // sealed - квалификатор, аналогичный const и volatile
    
    int interlocked_get_value(int sealed& v)
    {
        return const_cast<int&>(v); // в архитектуре с атомарным доступом к целому
    }
    
    int interlocked_increment(int sealed& v);
    
    int f()
    {
        ...
        
        int t;
        
        t = var1; // нельзя, доступ запрещён - квалификатор sealed
        t = interlocked_get_value(var1);
        
        var2 = t; // нельзя, доступ запрещён - квалификатор sealed
        interlocked_increment(var2);
     
        EnterCriticalSection(&cs);
    
        {
            unsealed var1, var2;
            
            // В данной области видимости у объектов var1, var2 квалификатор sealed снимается
            
            var2 = var1;
        }
    
        LeaveCriticalSection(&cs);
    
        ...
    }


    volatile лучше оставить для обработки сигналов и регистров, для чего он и предназначен.
    Я кончил, джентльмены, мне остается только поблагодарить вас за внимание.
    Re[4]: ужас
    От: MaximE Великобритания  
    Дата: 20.01.05 11:17
    Оценка:
    Tom wrote:

    []

    > Что такое "непрозрачные" функции,


    Те ф-ции, исходный код которых компилятору недоступен, или компилятор не может сделать выводов об эффектах ф-ции.

    > где о них упоминание в стандарте


    ISO IEC 9899 C99 Language Standard
    5.1.2 Program execution

    > и кем карантируется то, что ты сказал?


    Об этом позже.

    --
    Maxim Yegorushkin
    Posted via RSDN NNTP Server 1.9
    Re[6]: volatile у переменной класса
    От: MaximE Великобритания  
    Дата: 20.01.05 11:23
    Оценка:
    Andrew S wrote:

    > ME>Конечно, защитников volatile это не убедит, т.к. они скажут, что в ms знали особенности компилятора и нужные ключи компиляции, когда они компилировали ф-ции EnterCriticalSection et al.

    >
    > А что на нее глядеть? Она пользуется извне только для отладочных целей (соотв, когда никакой оптимизации и нет).

    Код ф-ций EnterCriticalSection et al компилировался с этим определением ст-ры.

    --
    Maxim Yegorushkin
    Posted via RSDN NNTP Server 1.9
    Re[7]: volatile у переменной класса
    От: Andrew S Россия http://alchemy-lab.com
    Дата: 20.01.05 11:39
    Оценка:
    >>
    >> А что на нее глядеть? Она пользуется извне только для отладочных целей (соотв, когда никакой оптимизации и нет).

    ME>Код ф-ций EnterCriticalSection et al компилировался с этим определением ст-ры.


    Это заявление сделано на основании анализа исходников, доступных в сети, или же просто домыслы?
    http://www.rusyaz.ru/pr — стараемся писАть по-русски
    Re[5]: Счетчики в CRITICAL_SECTION
    От: emusic Франция https://software.muzychenko.net/ru
    Дата: 20.01.05 11:42
    Оценка:
    Здравствуйте, MaximE, Вы писали:

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


    ME> LONG LockCount;

    ME> LONG RecursionCount;

    ME>Каунтеры не объявлены как volatile.


    А необязательно. Cache cogerency в x86 имеется, для работы с этими счетчиками в NTDLL используются lock-префиксы (в базовой версии DLL там nop'ы, в MP вставляются lock'и). На Alpha/PPC, соответственно, используются более другие способы.

    Вообще, какой смысл так упираться, пытаясь доказать ненужность volatile вообще, но почему-то посредством исключительно частных случаев?
    ... << RSDN@Home 1.1.4 beta 3 rev. 185>>
    Re[5]: ужас
    От: achp  
    Дата: 20.01.05 11:45
    Оценка:
    Здравствуйте, MaximE, Вы писали:

    ME>Он может утечь не явно.


    ME>("Непрозрачная") ф-ция может взять адрес возврата, по .pdb файлу определить, что это за вызывающая ф-ция, получить адрес ее фрейма и пробежаться по ее переменным и аргументам — no big deal.


    Это уже мошенничество. Если автор такое делает, то это из той же оперы, что и "assume no aliasing".
    Я кончил, джентльмены, мне остается только поблагодарить вас за внимание.
    Re[6]: ужас
    От: Andrew S Россия http://alchemy-lab.com
    Дата: 20.01.05 11:46
    Оценка:
    ME>Еще примерчик. Любая "непрозрачная" ф-ция может изменить errno. errno не объявлен volatile.

    Потому что для каждого потока он свой
    http://www.rusyaz.ru/pr — стараемся писАть по-русски
    Re[2]: Поведение C++ runtime
    От: emusic Франция https://software.muzychenko.net/ru
    Дата: 20.01.05 11:52
    Оценка:
    Здравствуйте, eao197, Вы писали:

    E>имеет ли право компилятор, встретив где-то в коде strlen посчитать, что он все знает про эту функцию (она же из стандартной библиотеки) и оптимизировать все, что находится вокруг нее?


    Сам по себе — конечно, нет. Но многие компиляторы имеют intrinsic-версии распространенных коротких функций, и strlen часто в их числе. Тогда вместо вызова генерируется инлайновый код. Чтобы подменить такую функцию, надо сказать компилятору, что такой замены делать не нужно. Для VC++ это #pragma function.
    ... << RSDN@Home 1.1.4 beta 3 rev. 185>>
    Re[5]: ужас
    От: Seriously Serious  
    Дата: 20.01.05 11:53
    Оценка:
    Здравствуйте, achp, Вы писали:

    A>Во-первых, из "прозрачности" ещё не следует, что можно "всё держать в регистрах". "Прозрачность", то есть доступность для компилятора тела данной функции, может позволить компилятору сделать вывод о том, какие объекты подвергаются модификации при её вызове, а какие — нет. А может и не позволить.

    В каких случаях?

    A>Во-вторых, тогда барьеры (и многопоточность вообще) станут просто невозможны.

    Вот я и об этом.
    Re[6]: Изменение errno
    От: emusic Франция https://software.muzychenko.net/ru
    Дата: 20.01.05 11:59
    Оценка:
    Здравствуйте, MaximE, Вы писали:

    ME>Любая "непрозрачная" ф-ция может изменить errno. errno не объявлен volatile.


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

    ME>("Непрозрачная") ф-ция может взять адрес возврата, по .pdb файлу определить, что это за вызывающая ф-ция, получить адрес ее фрейма и пробежаться по ее переменным и аргументам — no big deal.


    Тогда можно и проще — скастить функцию в указатель на другой прототип, вызвать — и нехай компилятор разгребает то, что в итоге получится
    ... << RSDN@Home 1.1.4 beta 3 rev. 185>>
    Re[7]: ужас
    От: MaximE Великобритания  
    Дата: 20.01.05 12:15
    Оценка:
    Andrew S wrote:

    > ME>Еще примерчик. Любая "непрозрачная" ф-ция может изменить errno. errno не объявлен volatile.

    >
    > Потому что для каждого потока он свой

    Да, это сакральное занание доступно единицам (в Линукс при многопоточности это вообще макрос вызова ф-ции).

    Я это привел к тому, что после вызова непрозрачных ф-ций компилятор будет перечитвать значение этой переменной, хотя она не объявлена volatile. (безотносительно к многопоточности)

    --
    Maxim Yegorushkin
    Posted via RSDN NNTP Server 1.9
    Re[7]: Изменение errno
    От: MaximE Великобритания  
    Дата: 20.01.05 12:16
    Оценка:
    emusic wrote:

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

    >
    > ME>Любая "непрозрачная" ф-ция может изменить errno. errno не объявлен volatile.
    >
    > Он внешний следовательно, компилятору принципиально не может быть известно количество желающих его модифицировать, и оптимизации он никак не подлежит.




    Мы все еще ждем от тебя примеров кода, подтверждающие, что при использовании синхронизации нужен еще и volatile.

    --
    Maxim Yegorushkin
    Posted via RSDN NNTP Server 1.9
    Re[12]: [2]: : volatile: а можно примеры?
    От: Andrew S Россия http://alchemy-lab.com
    Дата: 20.01.05 12:27
    Оценка:
    AS>>V2. Переменная объявлена не как volatile. Соотв, параметры InterlockedXxx без volatile (например, как это было в PSDK 2-х летней давности. Теперь это не так и вынуждает программистов использовать volatile для этих функций.

    A>С какой радости? Преобразования указателей от менее cv-квалифицированных к более cv-квалифицированным происходят неявно.


    Ну, не вынуждает, а поощряет, скажет так.
    http://www.rusyaz.ru/pr — стараемся писАть по-русски
    Re[13]: [2]: : volatile: а можно примеры?
    От: MaximE Великобритания  
    Дата: 20.01.05 12:37
    Оценка:
    Здравствуйте, Andrew S, Вы писали:

    AS>>>V2. Переменная объявлена не как volatile. Соотв, параметры InterlockedXxx без volatile (например, как это было в PSDK 2-х летней давности. Теперь это не так и вынуждает программистов использовать volatile для этих функций.


    A>>С какой радости? Преобразования указателей от менее cv-квалифицированных к более cv-квалифицированным происходят неявно.


    AS>Ну, не вынуждает, а поощряет, скажет так.


    Как конкретно поощряет?
    Re[14]: [2]: : volatile: а можно примеры?
    От: Andrew S Россия http://alchemy-lab.com
    Дата: 20.01.05 12:45
    Оценка:
    AS>>>>V2. Переменная объявлена не как volatile. Соотв, параметры InterlockedXxx без volatile (например, как это было в PSDK 2-х летней давности. Теперь это не так и вынуждает программистов использовать volatile для этих функций.

    A>>>С какой радости? Преобразования указателей от менее cv-квалифицированных к более cv-квалифицированным происходят неявно.


    AS>>Ну, не вынуждает, а поощряет, скажет так.


    ME>Как конкретно поощряет?


    http://www.rsdn.ru/Forum/Message.aspx?mid=982608&amp;only=1
    Автор: Шахтер
    Дата: 12.01.05
    http://www.rusyaz.ru/pr — стараемся писАть по-русски
    Re[3]: Поведение C++ runtime
    От: eao197 Беларусь http://eao197.blogspot.com
    Дата: 20.01.05 12:54
    Оценка:
    Здравствуйте, Костя Ещенко, Вы писали:

    КЕ>Объявление/определение функции из стандартной библиотеки С, например strlen, в глобальном или ::std неймспейсах с внешней компоновкой приводит к ub. Это значит что можно создать strlen только либо в своем неймспейсе, либо локальную, либо статическую (с внутренней компоновкой).

    КЕ>В 17.4.3 вообще куча страшилок, но new/delete и некоторые другие специально разрешено переопределять.

    Спасибо за информацию. Теперь буду знать.
    ... << RSDN@Home 1.1.4 beta 3 rev. 185>>


    SObjectizer: <микро>Агентно-ориентированное программирование на C++.
    Re[13]: [2]: : volatile: а можно примеры?
    От: achp  
    Дата: 20.01.05 13:04
    Оценка:
    Здравствуйте, Andrew S, Вы писали:

    AS>Ну, не вынуждает, а поощряет, скажет так.


    Не поощрает, а идёт навстречу.
    Я кончил, джентльмены, мне остается только поблагодарить вас за внимание.
    Re[14]: [2]: : volatile: а можно примеры?
    От: Andrew S Россия http://alchemy-lab.com
    Дата: 20.01.05 13:09
    Оценка:
    AS>>Ну, не вынуждает, а поощряет, скажет так.
    A>Не поощрает, а идёт навстречу.
    И чего ж она, болезная, раньше не шла, а теперь вот нате? Ужо какие-ить грабли обнаружила в закромах родины
    http://www.rusyaz.ru/pr — стараемся писАть по-русски
    Re[8]: Изменение errno
    От: emusic Франция https://software.muzychenko.net/ru
    Дата: 20.01.05 18:21
    Оценка:
    Здравствуйте, MaximE, Вы писали:

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


    Какой именно синхронизации? Если посредством внешних функций-примитивов, то я согласен, что очень сложно будет найти столь смелый оптимизатор, который решился бы протащить через вызов подобной функции сохраненное значение нелокальной переменной. Однако здесь ты уже, заметь, апеллируешь отнюдь не к стандарту (по которому, благодаря отсутствию там многопоточности, можно было бы в некоторых случаях такую оптимизацию делать), а к популярным реализациям, которые не враги себе, и заинтересованы, чтобы у народа работали минимально пристойные программы.

    Однако синхронизация не обязана быть на уровне ОС посредством ее примитивов. Она может быть, например, на голой аппаратуре — вроде того, как в ядре NT/2k/XP реализованы спинлоки. Реально они для эффективности сделаны на ассемблере, но могут быть сделаны и на C/C++. Тут без volatile никуда не денешься. А определив глобальную функцию, которая работает с volatile-переменной синхронизации, можно уже с помощью этой функции синхронизироваться без volatile.

    Я же говорю — общее и частное. С утверждением "в многопоточной среде, где синхронизация выполняется посредством внешних функций, разделяемые переменные защищать volatile не обязательно".
    ... << RSDN@Home 1.1.4 beta 3 rev. 185>>
    Re[9]: volatile
    От: Seriously Serious  
    Дата: 20.01.05 18:45
    Оценка:
    В таком случае, есть ли какое-нибудь полезное применение volatile на UDT? (в смысле, чтобы можно было только функции с volatile вызывать)
    Re[10]: volatile
    От: emusic Франция https://software.muzychenko.net/ru
    Дата: 20.01.05 19:14
    Оценка:
    Здравствуйте, Seriously Serious, Вы писали:

    SS>В таком случае, есть ли какое-нибудь полезное применение volatile на UDT? (в смысле, чтобы можно было только функции с volatile вызывать)


    А кто у нас такой UDT?
    ... << RSDN@Home 1.1.4 beta 3 rev. 185>>
    Re[9]: Изменение errno
    От: Аноним  
    Дата: 20.01.05 19:35
    Оценка:
    Здравствуйте, MaximE, Вы писали:

    izvinyajusj za translit. Tak kto okazalsya pravee?

    ME>MaximE wrote:


    >>

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

    ME>... или признаем твою неправоту по таймауту


    ME>--

    ME>Maxim Yegorushkin
    Re[11]: volatile
    От: Seriously Serious  
    Дата: 20.01.05 19:59
    Оценка:
    Здравствуйте, emusic, Вы писали:

    E>А кто у нас такой UDT?

    user-defined type
    Re[10]: [2]: : volatile: а можно примеры?
    От: c-smile Канада http://terrainformatica.com
    Дата: 20.01.05 20:26
    Оценка:
    Здравствуйте, eao197, Вы писали:

    E>А с этим я никогда и не спорил. Поэтому еще раз проясню свою позицию: я хочу увидеть реальные примеры (из реальных, а не тестовых примеров), когда использовались примитивы синхронизации, но приложение все равно работало не правильно до тех пор, пока не было использовано volatile. При этом меня не интересуют ни обработчики аппаратных прерываний, ни работа с железом через отображаемые в память порты ввода/вывода.


    E>Прошу не приводить примеров, когда компилятору специальными ключами явно указывали, что ни одна функция не имеет побочных эффектов. Применение такого ключа в многопоточной программе, ИМХО, является проявлением излишнего оптимизма программиста. Кроме того, такой пример я уже видел. Может есть что-то еще?


    На моей задаче aliasing оптимизация дает 16% прирост производительности. Поэтому без этой оптимизации я даже и не компилирую.
    http://terrainformatica.com/htmlayout

    Вот фрагмент кода который без volatile просто не компилируется: например метод locked::dec(volatile long& cnt);
    Использование критической секции вокруг mutex для проверки флагов active и terminate было протестировано и признано неоправданным — потеря производительности.

    Попытка использовать голые (не volatile) флаги вызывала очень странный behavior.
    Вообще когда multithreading нечто начинает вести себя странно — ищи где ты забыл поставить volatile.

    
    namespace tool {
    
    class thread_pool
    {
    private:
        array<HANDLE>         thread_handles;
        array<task*>          tasks;
        mutex                 guard;
        event                 got_something;
        volatile long         terminate;
        volatile long         active;
        
    public:
        thread_pool(int n_pool_size = 5):
            terminate(0),active(0)
    
        void add_task(task *t)
    
        void start()
        void stop()
        {
           locked::set(terminate, 1);
           while(active > 0)
           {
             got_something.signal();
             yield();
           }
        }
    
    protected:
        task* next_task();
    
        static DWORD WINAPI thread(LPVOID pParam)
        {
            thread_pool* pthis = static_cast<thread_pool*>(pParam);
            while(!pthis->terminate)
            {
                task *t = pthis->next_task();
                if(t)
                {
                   t->exec();
                   delete t;
                }
            }
            locked::dec(pthis->active);
            return 0;
        }
    };
    
    }
    Re[21]: volatile у переменной класса
    От: c-smile Канада http://terrainformatica.com
    Дата: 20.01.05 20:31
    Оценка:
    Здравствуйте, achp, Вы писали:

    A>Кстати, конкретный вопрос. Назовите тот библиотечный файл, в котором "сидит" тело функции WaitForSingleObject.


    Для с++ "тело" этой функции сидит в

    Windows NT/2000/XP: Included in Windows NT 3.1 and later.
    Windows 95/98/Me: Included in Windows 95 and later.
    Header: Declared in Winbase.h; include Windows.h.
    Library: Use Kernel32.lib.

    Re[21]: volatile у переменной класса
    От: c-smile Канада http://terrainformatica.com
    Дата: 20.01.05 20:33
    Оценка:
    Здравствуйте, achp, Вы писали:

    CS>>Как выглядит "барьер" в стандарте C++?


    A>Барьер в стандарте Си/Си++ отсутствует. Отсюда следует, что единственный способ, которым он может быть выражен — вызов некоторой функции.


    Что такое "некоторая функция"? Любая? Или какая?
    Есть какое-нибудь строгое определение алгоритма определения барьера?
    Re[11]: [2]: : volatile: а можно примеры?
    От: MaximE Великобритания  
    Дата: 20.01.05 21:13
    Оценка:
    c-smile wrote:

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

    >
    > E>А с этим я никогда и не спорил. Поэтому еще раз проясню свою позицию: я хочу увидеть реальные примеры (из реальных, а не тестовых примеров), когда использовались примитивы синхронизации, но приложение все равно работало не правильно до тех пор, пока не было использовано volatile. При этом меня не интересуют ни обработчики аппаратных прерываний, ни работа с железом через отображаемые в память порты ввода/вывода.
    >
    > E>Прошу не приводить примеров, когда компилятору специальными ключами явно указывали, что ни одна функция не имеет побочных эффектов. Применение такого ключа в многопоточной программе, ИМХО, является проявлением излишнего оптимизма программиста. Кроме того, такой пример я уже видел. Может есть что-то еще?

    Во-первых, ты не привел кода, который мы просили привести: код, который использует ф-ции синхронизации для доступа к разделяемым переменным, но не работает когда эти разделяемые переменные не volatile.

    > На моей задаче aliasing оптимизация дает 16% прирост производительности. Поэтому без этой оптимизации я даже и не компилирую.

    > http://terrainformatica.com/htmlayout
    >
    > Вот фрагмент кода который без volatile просто не компилируется: например метод locked::dec(volatile long& cnt);

    Вот тебе минимальный код, который вопреки твоим словам скомпилируется:

    long l;
    locked::dec(l);


    > Использование критической секции вокруг mutex для проверки флагов active и terminate было протестировано и признано неоправданным — потеря производительности.

    >
    > Попытка использовать голые (не volatile) флаги вызывала очень странный behavior.

    Почему не использовались InterlockedCompareExchangeRelease для чтения значений разделяемых переменных?

    Если бы ты воспользовался этими ф-циями и заставил бы компилятор использовать intrinsic версии, твой код был бы не менее быстрым. InterlockedCompareExchangeRelease развернется на текущих Intel процессорах в LOCK CMPXCHG. Если destination в кэше процессора, то на современных процессорах Intel на шину не будет даже выставлен LOCK# сигнал.

    Напротив же, ты воспользовался implementation defined семантикой volatile, сделав свой код гарантированно непереносимым на другие аппаратные платформы, поддерживаемые MS Windoze, компиляторы, а также следующие поколения процессоров Intel. Конечно, MS в лепешку разобъется, чтобы бинарники из кода такого качества работали на ее операционных системах и новейших процессорах Intel (при помощи MTRR), но в том режиме ты теряешь то, за что ты тут борешься — производительность.

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

    > Вообще когда multithreading нечто начинает вести себя странно — ищи где ты забыл поставить volatile.


    У меня есть чудесная мантра со 100% эффективностью от таких проблем:

    Забудь про volatile, когда ты используешь multithreading.


    --
    Maxim Yegorushkin
    Posted via RSDN NNTP Server 1.9
    Re[12]: [2]: : volatile: а можно примеры?
    От: c-smile Канада http://terrainformatica.com
    Дата: 20.01.05 22:31
    Оценка:
    ME>Во-первых, ты не привел кода, который мы просили привести: код, который использует ф-ции синхронизации для доступа к разделяемым переменным, но не работает когда эти разделяемые переменные не volatile.

    Просили привести реальный код где работают volatile. Я привел.
    Абстрактные примеры тебе тоже привели.
    Для любого разумного человека они убедительны. По идее.

    >> На моей задаче aliasing оптимизация дает 16% прирост производительности. Поэтому без этой оптимизации я даже и не компилирую.

    >> http://terrainformatica.com/htmlayout
    >>
    >> Вот фрагмент кода который без volatile просто не компилируется: например метод locked::dec(volatile long& cnt);

    ME>Вот тебе минимальный код, который вопреки твоим словам скомпилируется:


    ME>
    ME>long l;
    ME>locked::dec(l);
    ME>


    Нет, так как

    struct locked
    {
      static long dec(volatile long& v)
      {
        return InterlockedDecrement(&v);
      }
    }


    >> Использование критической секции вокруг mutex для проверки флагов active и terminate было протестировано и признано неоправданным — потеря производительности.

    >>
    >> Попытка использовать голые (не volatile) флаги вызывала очень странный behavior.

    ME>Почему не использовались InterlockedCompareExchangeRelease для чтения значений разделяемых переменных?


    А какая разница? Там их тоже volatile нужно обяъвлять

    PVOID InterlockedCompareExchangePointer (
      PVOID volatile *Destination,  // destination address
      PVOID Exchange,               // exchange value
      PVOID Comperand               // value to compare
    );


    Я пишу реальные многоплатформенные конструкции.
    Чем меньше внешних платформо зависимых функций тем мне легче.

    volatile поддерживается и VC и GCC — т.е. это реальная платформонезависимость. Меня устраивает. И это работает.

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


    Знаешь, Макс, в моем багаже законченных продуктов
    есть например специализированный FTP сервер который работает без перезагрузки машины
    уже 14 месяцев с очень хорошим трафиком. Это я к тому что я примерно представляю как программировать multithreaded applications.

    И кстати обрати внимание что тебе здесь оппонируют люди которые *реально* занимаются multithreading. emusic (респект) например.

    >> Вообще когда multithreading нечто начинает вести себя странно — ищи где ты забыл поставить volatile.


    ME>У меня есть чудесная мантра со 100% эффективностью от таких проблем:

    ME>

    ME>Забудь про volatile, когда ты используешь multithreading.


    Я не говорю что без volatile нельзя написать multihreading код.
    Я говорю — volatile есть, описан в стандарте языка, поддерживается нужными мне компиляторами и реально помогает мне писать эффективный код (простой, надежный, human readable).

    Естесственно ты волен и вправе остваться при своем мнении. Только
    вот эту вот максиму "Забудь про volatile, когда ты используешь multithreading" ты лучше не пой на интервью по С++.
    Тебя сразу спросят про как вызвать тогда InterlockedIncrement и тебе нужно будет долго объяснять "что конкретно ты имеешь ввиду".

    Вот например как реализуются barriers c помощью volatile переменных:

    http://docs.hp.com/en/B3909-90003/apas04.html
    Re[5]: ужас
    От: Шахтер Интернет  
    Дата: 21.01.05 01:43
    Оценка:
    Здравствуйте, achp, Вы писали:

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


    SS>>А если ВСЕ функции станут прозрачными и компилятор будет ВСЁ держать в регистрах?


    A>Во-первых, из "прозрачности" ещё не следует, что можно "всё держать в регистрах". "Прозрачность", то есть доступность для компилятора тела данной функции, может позволить компилятору сделать вывод о том, какие объекты подвергаются модификации при её вызове, а какие — нет. А может и не позволить.


    A>Во-вторых, тогда барьеры (и многопоточность вообще) станут просто невозможны.


    Это почему ещё?
    ... << RSDN@Home 1.1.0 stable >>
    В XXI век с CCore.
    Копай Нео, копай -- летать научишься. © Matrix. Парадоксы
    Re[6]: volatile у переменной класса
    От: alnsn Великобритания http://nasonov.blogspot.com
    Дата: 21.01.05 08:57
    Оценка:
    Здравствуйте, c-smile, Вы писали:

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


    >>> Прохождение sequence point отнюдь не гарантирует, что состояния всех объектов в этой точке будут непременно отражены в памяти — это гарантируется только для volatile-объектов.


    ME>>Это не гарантируется большинством современных процессоров.


    CS>Т.е. ты утверждаешь что в "большинстве современных процессоров" нет операции

    CS>записи регистра в память? Или я не понял чего.

    Эта операция необходима, но не достаточна. Из того, что процессор записал регистр в память не следует, что остальные процессоры
    сразу ее прочитают.
    Re[2]: читаем про volatile
    От: alnsn Великобритания http://nasonov.blogspot.com
    Дата: 21.01.05 09:06
    Оценка:
    Здравствуйте, MaximE, Вы писали:

    ME>Вобщем, все вдумчиво читаем.


    Вот еще
    http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1738.pdf
    сжато, но есть ответы (или хотя бы намеки) на некоторые вопросы
    Re[12]: [2]: : volatile: а можно примеры?
    От: alnsn Великобритания http://nasonov.blogspot.com
    Дата: 21.01.05 10:37
    Оценка:
    Здравствуйте, achp, Вы писали:

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


    AS>>V2. Переменная объявлена не как volatile. Соотв, параметры InterlockedXxx без volatile (например, как это было в PSDK 2-х летней давности. Теперь это не так и вынуждает программистов использовать volatile для этих функций.


    A>С какой радости? Преобразования указателей от менее cv-квалифицированных к более cv-квалифицированным происходят неявно.


    LONG InterlockedExchange(
      LONG volatile* Target,
      LONG Value
    );


    Указатель здесь не volatile. Он всего-лишь указывает на LONG volatile.
    Здесь это не страшно, но если нужно не только LONG значение менять, но и указатель иногда перекидывать на другое значение, то надо делать так:
    LONG volatile* volatile p;

    Но здесь одним вызовом InterlockedExchange уже не обойдешься.
    Re[22]: volatile у переменной класса
    От: Аноним  
    Дата: 21.01.05 10:41
    Оценка:
    Здравствуйте, c-smile, Вы писали:

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


    A>>Кстати, конкретный вопрос. Назовите тот библиотечный файл, в котором "сидит" тело функции WaitForSingleObject.


    CS>Для с++ "тело" этой функции сидит в


    CS>

    CS> Windows NT/2000/XP: Included in Windows NT 3.1 and later.
    CS> Windows 95/98/Me: Included in Windows 95 and later.
    CS> Header: Declared in Winbase.h; include Windows.h.
    CS> Library: Use Kernel32.lib.


    Там сидит шлюз на неё. Тело сидит в kernek32 или ntdll, смотря что за система.
    Re[23]: volatile у переменной класса
    От: Andrew S Россия http://alchemy-lab.com
    Дата: 21.01.05 10:51
    Оценка:
    CS>>Для с++ "тело" этой функции сидит в

    CS>>

    CS>> Windows NT/2000/XP: Included in Windows NT 3.1 and later.
    CS>> Windows 95/98/Me: Included in Windows 95 and later.
    CS>> Header: Declared in Winbase.h; include Windows.h.
    CS>> Library: Use Kernel32.lib.


    А>Там сидит шлюз на неё. Тело сидит в kernek32 или ntdll, смотря что за система.


    Хотел бы я видеть систему, где эта функция в ntdll.dll

    На самом деле, в lib в данном случае лишь указания линковщику на то, в какой dll находится эта функция + ее название\ord. Так что без дополнительных телодвижений распарсить тело функции действительно сложно — да и не нужно, оно ж зависит от версии системы. Так что, конечно, в этом случае компилятор обязан следовать своему внутреннему описанию побочных эффектов данной функции (помимо изменяемых регистров, которые следуют из соглашений вызова), либо, если это нужно, предполагать наихудший вариант. Кстати, интересной мыслью было бы размещать такую информацию непосредственно в lib файлах.
    http://www.rusyaz.ru/pr — стараемся писАть по-русски
    Re[24]: volatile у переменной класса
    От: Аноним  
    Дата: 21.01.05 14:34
    Оценка:
    Здравствуйте, Andrew S, Вы писали:

    CS>>>Для с++ "тело" этой функции сидит в


    CS>>>

    CS>>> Windows NT/2000/XP: Included in Windows NT 3.1 and later.
    CS>>> Windows 95/98/Me: Included in Windows 95 and later.
    CS>>> Header: Declared in Winbase.h; include Windows.h.
    CS>>> Library: Use Kernel32.lib.


    А>>Там сидит шлюз на неё. Тело сидит в kernek32 или ntdll, смотря что за система.


    AS>Хотел бы я видеть систему, где эта функция в ntdll.dll


    Мои извинения, спутал с Enter/LeaveCriticalSection. WFSO реализована в kernel32.

    AS>На самом деле, в lib в данном случае лишь указания линковщику на то, в какой dll находится эта функция + ее название\ord. Так что без дополнительных телодвижений распарсить тело функции действительно сложно — да и не нужно, оно ж зависит от версии системы. Так что, конечно, в этом случае компилятор обязан следовать своему внутреннему описанию побочных эффектов данной функции (помимо изменяемых регистров, которые следуют из соглашений вызова), либо, если это нужно, предполагать наихудший вариант. Кстати, интересной мыслью было бы размещать такую информацию непосредственно в lib файлах.
    Re[25]: volatile у переменной класса
    От: Andrew S Россия http://alchemy-lab.com
    Дата: 21.01.05 15:16
    Оценка:
    А>>>Там сидит шлюз на неё. Тело сидит в kernek32 или ntdll, смотря что за система.

    AS>>Хотел бы я видеть систему, где эта функция в ntdll.dll


    А>Мои извинения, спутал с Enter/LeaveCriticalSection. WFSO реализована в kernel32.


    Нет, там тоже ее тела нет. Ее тело (в случае виннт) живет в ntoskrn. В kernel32 и в ntdll — переходники. В kernel32 это обычная заглушка, а в ntdll — шлюз. И Enter\LeaveCriticalSection тоже на самом деле ведет в итоге в ntdll, но в отличие от, реализована в ntdll.dll (RtlEnter\RtlLeaveCriticalSection)
    http://www.rusyaz.ru/pr — стараемся писАть по-русски
    Re[14]: [2]: : volatile: а можно примеры?
    От: c-smile Канада http://terrainformatica.com
    Дата: 21.01.05 17:21
    Оценка:
    Здравствуйте, eao197, Вы писали:

    ОК.

    Я так понимаю что потребности в interlocked* у вас в проекте просто не возникало...
    Т.е. вы обходитесь примитивами синхронизации верхнего уровня.

    давай я еще раз повторю из моего предыдущего сообщения.

    Я не говорю что без volatile нельзя написать multihreading код.
    Я говорю — volatile есть, описан в стандарте языка, поддерживается нужными мне компиляторами и реально помогает мне писать эффективный код (простой, надежный, human readable).


    Без volatile — можно, если производительность кода не есть mission critical
    или если достаточно примитивов и barriers уже кем-то написаныых с пом. того же volatile
    http://docs.hp.com/en/B3909-90003/apas04.html
    Re[14]: [2]: : volatile: а можно примеры?
    От: c-smile Канада http://terrainformatica.com
    Дата: 21.01.05 17:38
    Оценка:
    Здравствуйте, MaximE, Вы писали:

    >>>> На моей задаче aliasing оптимизация дает 16% прирост производительности. Поэтому без этой оптимизации я даже и не компилирую.

    >>>> http://terrainformatica.com/htmlayout

    ME>С этой опцией у тебя даже однопоточные программы будут глючить — поэтому тебе нужен volatile.


    Это если подходить к делу без ума.
    Re[12]: [2]: : volatile: а можно примеры?
    От: c-smile Канада http://terrainformatica.com
    Дата: 21.01.05 17:46
    Оценка:
    Здравствуйте, eao197, Вы писали:

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


    E>Спасибо за ваш пример. Но как и пример What-а
    Автор: What
    Дата: 18.01.05
    его можно считать очень платформенно-зависимым. Ведь вы из-за соображений производительности отказались от использования штатных примитивов синхронизации (критические секции или mutex-а), а сделали свои. И естественно, были вынуждены использовать volatile, поскольку в отсутствии обращений к внешним функциям ничего не запрещало компилятору "оптимизировать" работу с переменными.


    Я использую штатные там где это действительно надо.

    namespace tool 
    {
    
    #ifdef WIN32
    class mutex { 
        CRITICAL_SECTION cs;
     public:
        void lock() { 
            EnterCriticalSection(&cs);
        } 
        void unlock() {
            LeaveCriticalSection(&cs);
        } 
        mutex() { 
            InitializeCriticalSection(&cs);
        }   
        ~mutex() { 
            DeleteCriticalSection(&cs);
        }
    };
    
    struct event 
    { 
        HANDLE h;
    
        event() { 
            h = CreateEvent(NULL, FALSE, FALSE, NULL);
        }
        ~event() { 
            CloseHandle(h);
        }
        void signal() { 
            SetEvent(h);
        }
        void pulse() { 
            PulseEvent(h);
        }
    
        void wait(mutex& m) { 
            m.unlock();
            WaitForSingleObject(h, INFINITE);
            m.lock();
        }
        void wait() { 
            WaitForSingleObject(h, INFINITE);
        }
        
    };
    
    #else // pthreads
    
    class mutex { 
        int             count;
        pthread_t       owner;
        pthread_mutex_t cs;
    
        friend class event_t;
     public:
        void lock() { 
        pthread_t self = pthread_self();
        if (owner != self) { 
            pthread_mutex_lock(&cs); 
            owner = self;
        }
        count += 1;
        }
        void unlock() { 
        assert(pthread_self() == owner);
        if (--count == 0) {
            owner = 0;
            pthread_mutex_unlock(&cs);
        } 
        }
        mutex() { 
        pthread_mutex_init(&cs, NULL);
        }   
        ~mutex() { 
        pthread_mutex_destroy(&cs);
        }
    };
    
    class event { 
        pthread_cond_t cond;
    
       public:
        event() { 
        pthread_cond_init(&cond, NULL);
        }
        ~event() { 
        pthread_cond_destroy(&cond);
        }
        void signal() { 
        pthread_cond_signal(&cond);
        }
        void wait(mutex_t& m) { 
        pthread_t self = pthread_self();
        assert(m.owner == self && m.count == 1);
        m.count = 0;
        m.owner = 0;
        pthread_cond_wait(&cond, &m.cs);
        m.count = 1;
        m.owner = self;
        }
    };
    
    #endif

    Код практически 1 в 1 нагло заимствован из SAL Кости Книжника.
    Re[14]: [2]: : volatile: а можно примеры?
    От: c-smile Канада http://terrainformatica.com
    Дата: 21.01.05 20:21
    Оценка:
    Здравствуйте, MaximE, Вы писали:

    ME>
  • Док-ция к процессору, здесь — IA-32 Intel® Architecture Software Developer's Manual Volume 3: System Programming Guide. Здесь нам черным по белому пишут в §7.2.4:
    ME>

    ME>It is recommended that software written to run on Pentium 4, Intel Xeon, and P6 family processors assume the processor-ordering model or a weaker memory-ordering model. The Pentium 4, Intel Xeon, and P6 family processors do not implement a strong memory-ordering model, except when using the UC memory type. Despite the fact that Pentium 4, Intel Xeon, and P6 family processors support processor ordering, Intel does not guarantee that future processors will support this model. To make software portable to future processors, it is recommended that operating systems provide critical region and resource control constructs and API s (application program interfaces) based on I/O, locking, and/or serializing instructions be used to synchronize access to shared areas of memory in multiple-processor systems. Also, software should not depend on processor ordering in situations where the system hardware does not support this memory-ordering model.


    Ты сам вообще внимательно прочел что написано?

    Группа функций Interlocked* как раз является импелементацией "...and/or serializing instructions be used..."

    Производитель компилятора тебе сказал что он хочет видеть переменную отдаваемую в InterlockedIncrement
    объявленную как volatile. Ты также знаешь что оптимизатор будет относится к чтению volatile переменных с определенным
    пиететом.

    Это твое личное дело слушать рекомендации или нет.

    Только не говори что "volatile вредит". Встречное предложение: покажи мне реальный код где volatile вредно. Или не portable.
    Если не portable, то пожалуйста приведи portable механизмы синхронизации.
  • Re[3]: читаем про volatile
    От: MaximE Великобритания  
    Дата: 22.01.05 11:34
    Оценка:
    alnsn wrote:

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

    >
    > ME>Вобщем, все вдумчиво читаем.
    >
    > Вот еще
    > http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1738.pdf
    > сжато, но есть ответы (или хотя бы намеки) на некоторые вопросы

    И еще Memory model for multithreaded C++

    --
    Maxim Yegorushkin
    Posted via RSDN NNTP Server 1.9
    Re[15]: [2]: : volatile: а можно примеры?
    От: MaximE Великобритания  
    Дата: 22.01.05 22:02
    Оценка:
    c-smile wrote:

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

    >
    > ME>
  • Док-ция к процессору, здесь — IA-32 Intel® Architecture Software Developer's Manual Volume 3: System Programming Guide. Здесь нам черным по белому пишут в §7.2.4:
    > ME>

    > ME>It is recommended that software written to run on Pentium 4, Intel Xeon, and P6 family processors assume the processor-ordering model or a weaker memory-ordering model. The Pentium 4, Intel Xeon, and P6 family processors do not implement a strong memory-ordering model, except when using the UC memory type. Despite the fact that Pentium 4, Intel Xeon, and P6 family processors support processor ordering, Intel does not guarantee that future processors will support this model. To make software portable to future processors, it is recommended that operating systems provide critical region and resource control constructs and API s (application program interfaces) based on I/O, locking, and/or serializing instructions be used to synchronize access to shared areas of memory in multiple-processor systems. Also, software should not depend on processor ordering in situations where the system hardware does not support this memory-ordering model.
    > ME>

    >
    > Ты сам вообще внимательно прочел что написано?
    >
    > Группа функций Interlocked* как раз является импелементацией "...and/or serializing instructions be used..."
    >
    > Производитель компилятора тебе сказал что он хочет видеть переменную отдаваемую в InterlockedIncrement объявленную как volatile.

    В документации это желание/требование никак не выражено.

    size_t strlen(char const*);


    Значит ли это объявленние ф-ции, что ее автор "хочет видеть" только константные строки? Или это значит, что автору наплевать, константная ли строка?

    Ключевых слов C++ недостаточно, чтобы выразить только ими без какой либо дополнительной док-ции требования, гарантии и ограничения функции.

    > Ты также знаешь что оптимизатор будет относится к чтению volatile переменных с определенным пиететом.


    Я не буду использовать volatile, пока мне четко не скажут в док-ции к компилятору/api, что это необходимо.




    Больше ничего нового я в ближайшее время здесь не скажу.

    --
    Maxim Yegorushkin
    Posted via RSDN NNTP Server 1.9
  • Re[16]: [2]: : volatile: а можно примеры?
    От: c-smile Канада http://terrainformatica.com
    Дата: 22.01.05 22:19
    Оценка:
    Здравствуйте, MaximE, Вы писали:

    ME>Я не буду использовать volatile, пока мне четко не скажут в док-ции к компилятору/api, что это необходимо.


    Документация к компилятору Visual C++

    int volatile nVint;

    Objects declared as volatile are not used in optimizations because their value can change at any time. The system always reads the current value of a volatile object at the point it is requested, even if the previous instruction asked for a value from the same object. Also, the value of the object is written immediately on assignment.

    Re[17]: [2]: : volatile: а можно примеры?
    От: MaximE Великобритания  
    Дата: 22.01.05 22:45
    Оценка:
    c-smile wrote:

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

    >
    > ME>Я не буду использовать volatile, пока мне четко не скажут в док-ции к компилятору/api, что это необходимо.
    >
    > Документация к компилятору Visual C++
    >
    >

    > int volatile nVint;
    >
    > Objects declared as volatile are not used in optimizations because their value can change at any time. The system always reads the current value of a volatile object at the point it is requested, even if the previous instruction asked for a value from the same object. Also, the value of the object is written immediately on assignment.


    Андрей, я подразумеваю, что русский мы понимаем на равных, и английский мы знаем достаточно, хотя бы для того, чтобы после фразы "would you like to go out with me tonight?" на следущее утро также накормить девушку завтраком?

    Так вот, где в приведенной тобой цитате сказано

    ... пока мне четко не скажут в док-ции к компилятору/api, что это необходимо


    --
    Maxim Yegorushkin
    Posted via RSDN NNTP Server 1.9
    Re[18]: [2]: : volatile: а можно примеры?
    От: c-smile Канада http://terrainformatica.com
    Дата: 23.01.05 01:32
    Оценка:
    Здравствуйте, MaximE, Вы писали:

    >>

    >> int volatile nVint;
    >>
    >> Objects declared as volatile are not used in optimizations because their value can change at any time. The system always reads the current value of a volatile object at the point it is requested, even if the previous instruction asked for a value from the same object. Also, the value of the object is written immediately on assignment.


    ME>Андрей, я подразумеваю, что русский мы понимаем на равных, и английский мы знаем достаточно, хотя бы для того, чтобы после фразы "would you like to go out with me tonight?" на следущее утро также накормить девушку завтраком?


    ME>Так вот, где в приведенной тобой цитате сказано

    ME>

    ME>... пока мне четко не скажут в док-ции к компилятору/api, что это необходимо


    OK. Let's rephrase this as: If you want to assure the value of variable to appear at its memory location upon assignment you must
    declare this variable as a volatile. According to VC++ documentation this is the only legal way to exclude assignment to it from any optimizations.

    Это если следовать формальной логике.

    Ты пойми, никакого формального же описания "барьеров" в документации VC++ просто нет. Собственно как и ни в каком другом компиляторе.
    Единственное что есть это volatile.

    "Барьер" это некая абстракция верхнего уровня которая имплементируется везде где я только это видел на volatile переменных.

    Вот например свежий патч к GCC по поводу создания барьеров:

    My patch for PR c++/13684 implemented thread-safe initialization of C++
    static local variables, using the double-checked locking pattern:

    http://gcc.gnu.org/ml/gcc-patches/2004-12/msg01888.html
    Re:еще 5 копеек
    От: Dr.Gigabit  
    Дата: 24.01.05 11:25
    Оценка:
    Не знаю, как соотносятся volatile у C++ и С#, но вот из документации FW 2.0 SDK:


    The volatile keyword indicates that a field can be modified in the program by something such as the operating system, the hardware, or a concurrently executing thread.
    .......

    The system always reads the current value of a volatile object at the point it is requested, even if the previous instruction asked for a value from the same object. Also, the value of the object is written immediately on assignment.

    The volatile modifier is usually used for a field that is accessed by multiple threads without using the lock statement to serialize access. Using the volatile modifier ensures that one thread retrieves the most up-to-date value written by another thread.

    ... << RSDN@Home 1.1.4 @@subversion >>
    Re[20]: [2]: : volatile: а можно примеры?
    От: MaximE Великобритания  
    Дата: 24.01.05 20:50
    Оценка:
    MaximE wrote:

    И postы от Doug Harrison Microsoft MVP — Visual C++
    http://groups-beta.google.com/group/microsoft.public.vc.mfc/msg/37c71acb8f8a6feb?dmode=source

    --
    Maxim Yegorushkin
    Posted via RSDN NNTP Server 1.9
    Re[8]: volatile у переменной класса
    От: maq Россия http://www.maqdev.com
    Дата: 21.02.05 09:40
    Оценка:
    >>> А что на нее глядеть? Она пользуется извне только для отладочных целей (соотв, когда никакой оптимизации и нет).

    ME>>Код ф-ций EnterCriticalSection et al компилировался с этим определением ст-ры.


    AS>Это заявление сделано на основании анализа исходников, доступных в сети, или же просто домыслы?
    <RSDN@Home ME> FooBar2k: silent
    Re[19]: [2]: : volatile: а можно примеры?
    От: MaximE Великобритания  
    Дата: 20.06.05 07:26
    Оценка:
    Здравствуйте, c-smile, Вы писали:

    []

    CS>Ты пойми, никакого формального же описания "барьеров" в документации VC++ просто нет. Собственно как и ни в каком другом компиляторе.

    CS>Единственное что есть это volatile.

    CS>"Барьер" это некая абстракция верхнего уровня которая имплементируется везде где я только это видел на volatile переменных.



    http://msdn2.microsoft.com/library/z055s48f(en-us,vs.80).aspx
    http://msdn2.microsoft.com/library/65tt87y8(en-us,vs.80).aspx

    The Visual C++ compiler is free to perform any optimization that preserves the meaningful outputs of the program in single-threaded execution. These barriers are provided to block optimization of reads and writes at specific points in a program. This is similar to marking that memory "volatile" only more performant (when usable) because it only forces reads and writes to complete at specific points in a program, rather than globally.


    --
    Maxim Yegorushkin
    Re[20]: [2]: : volatile: а можно примеры?
    От: Alexey_ch Швейцария  
    Дата: 20.06.05 13:09
    Оценка:
    Здравствуйте, MaximE, Вы писали:

    ME>

    ME>The Visual C++ compiler is free to perform any optimization that preserves the meaningful outputs of the program in single-threaded execution. These barriers are provided to block optimization of reads and writes at specific points in a program. This is similar to marking that memory "volatile" only more performant (when usable) because it only forces reads and writes to complete at specific points in a program, rather than globally.


    Через полгода мнение насчет volatile не изменилось?
    ... << RSDN@Home 1.1.4 beta 7 rev. 0>>
    Re[14]: volatile у переменной класса
    От: Erop Россия  
    Дата: 20.06.05 14:27
    Оценка:
    Здравствуйте, MaximE, Вы писали:

    ME>Этот код — некорректный многопоточный код, так как он не применяет синхронизацию для доступа к переменной.

    А зачем нужна синхронизация, для этого случая? Ну максимум может быть нужно читать/писать флаг Interkocked функциями.
    Но при чём тут синхронизация и волотайл?

    А вот читать оно действительно не сможет, пока компилятор точно в память не положит переменную.
    Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
    Re[21]: [2]: : volatile: а можно примеры?
    От: AndreyT  
    Дата: 20.06.05 21:20
    Оценка:
    Может, я чего в данной теме и просмотрел.
    Но хотелось бы напомнить высокому собранию, что volatile растёт из MMIO для PDP-11.
    Те, кто DDJ внимательно читают, видимо помнят.
    Остальным могу привести ссылку, там в тексте есть вставка под названием "volatile: A Brief History"

    http://www.aristeia.com/Papers/DDJ_Jul_Aug_2004.pdf
    Re[3]: : volatile: а можно примеры?
    От: Аноним  
    Дата: 20.06.05 21:43
    Оценка:
    Здравствуйте, MaximE, Вы писали:


    ME>С использованием средств синхронизации никаких проблем без volatile нет и быть не должно.


    Ну это две разные вещи volatile и синхронизация.

    Синхронизация применяется когда два потока могут одновременно изменить значение переменной.
    volatile говорит компилятору что надо всегда считать значение переменной из памяти и не кэшировать её.

    Ну чем синхронизация поможет если компилятор закэшировал значение в регистр.
    пример (псевдокод):

    LOCK(m_a)
    m_a = 5;
    UNLOCK(m_a)

    while(true)
    {
    LOCK(m_a)
    if( m_a != 5 )
    break;
    UNLOCK(m_a)
    }

    Вот этот цикл будет всю жизнь крутиться даже если второй thread установил m_a = 6.

    И всё синхронизированно вроде.


    Так что не путайте людей пожалуйста. В MSDN всё хорошо написано.

    George.
    Re[9]: Изменение errno
    От: Аноним  
    Дата: 20.06.05 21:58
    Оценка:
    Здравствуйте, MaximE, Вы писали:

    ME>MaximE wrote:


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


    ME>... или признаем твою неправоту по таймауту


    Хоть я и не тот от кого ты ждал примера но я его всё равно привел
    http://rsdn.ru/forum/message.1232106.aspx

    Снова посторюсь. volatile и Синхронизация две разные вещи. И применять одно или другое никак не связано друг с другом.

    George.
    Re[13]: [2]: : volatile: а можно примеры?
    От: Erop Россия  
    Дата: 21.06.05 00:22
    Оценка:
    Здравствуйте, alnsn, Вы писали:

    A>
    A>LONG InterlockedExchange(
    A>  LONG volatile* Target,
    A>  LONG Value
    A>);
    A>


    A>Указатель здесь не volatile. Он всего-лишь указывает на LONG volatile.

    A>Здесь это не страшно, но если нужно не только LONG значение менять, но и указатель иногда перекидывать на другое значение, то надо делать так:
    A>
    LONG volatile* volatile p;

    A>Но здесь одним вызовом InterlockedExchange уже не обойдешься.

    Интересно, и как эе ты собираешься "перекидывать" формальный параметр функции?
    Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
    Re[2]: volatile у переменной класса
    От: execve  
    Дата: 21.06.05 03:48
    Оценка:
    Здравствуйте, MaximE, Вы писали:

    ME>volatile не имеет никакого отношения к multithreading, поэтому его применение в этой ситуации не только бесполезно, но может быть и вредно, так как с volatile компилятор не сможет соптимизировтать доступ к этой переменной. Но если один из потоков изменяет переменную, синхронизация при помощи мютексов обязательна.


    bool flag;
    
    // thread 1
    ...
    flag = false;
    while(!flag) {
        ...
        sleep(1);
    }
    ...
    
    //thread 2
    ...
    flag = true;
    ...


    VC6 в процессе оптимизации переносил переменную flag в первом потоке в регистр, в результате чего цикл оказывался вечным.
    И был вобщем-то прав.

    Можешь добавить мьютексов по вкусу — проблему это не решит.
    Re[4]: : volatile: а можно примеры?
    От: Alexey_ch Швейцария  
    Дата: 21.06.05 07:24
    Оценка:
    Здравствуйте, <Aiiiei>, Вы писали:

    Aii>Синхронизация применяется когда два потока могут одновременно изменить значение переменной.

    Aii>volatile говорит компилятору что надо всегда считать значение переменной из памяти и не кэшировать её.

    Aii>Ну чем синхронизация поможет если компилятор закэшировал значение в регистр.

    Aii>пример (псевдокод):

    Volatile придумали давно, когда программисты были умнее компиляторов. На самом деле приведенный тобой код будет работать сегодня (например на VC 7.1) корректно даже без "volatile". Хотя если беспокоиться о портабельности исходников, то лучше это ключевое слово использовать там, где память доступна нескольким потокам одновременно.
    ... << RSDN@Home 1.1.4 beta 7 rev. 0>>
    Re[5]: : volatile: а можно примеры?
    От: Аноним  
    Дата: 21.06.05 11:35
    Оценка:
    Здравствуйте, Alexey_ch, Вы писали:

    A_>Volatile придумали давно, когда программисты были умнее компиляторов. На самом деле приведенный тобой код будет работать сегодня (например на VC 7.1) корректно даже без "volatile". Хотя если беспокоиться о портабельности исходников, то лучше это ключевое слово использовать там, где память доступна нескольким

    потокам одновременно.

    Не понял. А почему он будет работать?
    Из моего опыта он работать не будет если включена оптимизация.

    George.
    Re[3]: volatile у переменной класса
    От: eao197 Беларусь http://eao197.blogspot.com
    Дата: 21.06.05 19:26
    Оценка:
    Здравствуйте, <Аноним>, Вы писали:

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


    ME>>Рихтер ошибался.


    ME>>volatile не имеет никакого отношения к multithreading, поэтому его применение в этой ситуации не только бесполезно, но может быть и вредно, так как с volatile компилятор не сможет соптимизировтать доступ к этой переменной. Но если один из потоков изменяет переменную, синхронизация при помощи мютексов обязательна.



    А>Тут Максим вы не правы. Рихтер не ошибался. И синхронизировать не обящательно. Всё от ситуации зависит.


    Имхо, тут как раз не правы вы.

    А>пример. Имеем два потока один чего то делает и по завершению операции устанавливает переменную m_bDone в true.

    А>второй поток пытается синхронизироваться с первым и крутит пустой цикл до тех пор пока m_bDone != true;

    Немного странный способ синхронизации, не находите?

    А>Если переменная не объявлена как volatile то цикл

    А>while(!m_bDone); будет всю жизнь крутиться. Так как компилятор не дурак. Он один раз прочтет m_bDone в регистр (кэш процессора) и потом каждый раз будет его проверять. И то что m_bDone уже давно была установлена другим потоком никогда не узнает.
    А>Если переменая объявлена как volatile то компилятору это команда что каждый раз перед обращением к этой переменной её нужно считать из памяти.

    Это уже обсуждалось внутри темы: Реальный пример использования volatile
    Автор: What
    Дата: 18.01.05
    ... << RSDN@Home 1.1.4 beta 7 rev. 447>>


    SObjectizer: <микро>Агентно-ориентированное программирование на C++.
    Re[4]: volatile у переменной класса
    От: Аноним  
    Дата: 21.06.05 20:12
    Оценка:
    Здравствуйте, eao197, Вы писали:

    E>Имхо, тут как раз не правы вы.


    Ну я так понимаю что "Имхо" это очевидно. А я говорю что Очевидно что рихтер прав а MaximE не прав. И что?
    то слово очевидно поменяло. Может теперь подерёмся чтоб выяснить прав рихтер или нет (Пытаюсь обяснить что без примеров слова "очевидно" ничего не дают.)

    E>Немного странный способ синхронизации, не находите?


    Не нахожу. Программы пишуться разными людьми и о вкусах не спорят.

    E>Это уже обсуждалось внутри темы: Реальный пример использования volatile
    Автор: What
    Дата: 18.01.05


    что то почитал я понял что люди пришли к согласию что volatile и синхронизация разные вещи.

    George.
    Re[5]: volatile у переменной класса
    От: eao197 Беларусь http://eao197.blogspot.com
    Дата: 21.06.05 21:02
    Оценка:
    Здравствуйте, <Аноним>, Вы писали:

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


    E>>Немного странный способ синхронизации, не находите?


    А>Не нахожу. Программы пишуться разными людьми и о вкусах не спорят.


    E>>Это уже обсуждалось внутри темы: Реальный пример использования volatile
    Автор: What
    Дата: 18.01.05


    А>что то почитал я понял что люди пришли к согласию что volatile и синхронизация разные вещи.


    См. Re[3]: volatile у переменной класса
    Автор: Alex Alexandrov
    Дата: 22.06.05
    -- там очень классное резюме для всей ветки сделано.
    ... << RSDN@Home 1.1.4 beta 7 rev. 447>>


    SObjectizer: <микро>Агентно-ориентированное программирование на C++.
    Re[13]: volatile у переменной класса
    От: Михаил  
    Дата: 22.06.05 03:41
    Оценка:
    Здравствуйте, MaximE, Вы писали:

    ME>В будущем для Intel и в настоящем для многих других процессоров, volatile точно не поможет, так как на Intel он опирается на две processor dependent фичи: на memory ordering и когерентность кешей (cache snooping выше).


    Значит, появятся другие фичи. Например, ключи в компиляторе. Понятие volatile есть, и оно обязано быть реализовано. Реализовано так, как написано в MSDN, исходя из чего и применяется в реальных программах. А тонкости стандарта большинство разработчиков не интересует. Никто не будет выпускать проц, под который придется переписывать софт. Тем более Intel. В данном случае истина — мнение большинства.
    ...А отсюда наливаем, когда рецепт написан совсем неразборчиво...
    Re[4]: volatile у переменной класса
    От: Mr. None Россия http://mrnone.blogspot.com
    Дата: 22.06.05 03:59
    Оценка:
    Здравствуйте, Alex Alexandrov, Вы писали:

    AA>Ох, зря эту ветку подняли... Рекомендую прочитать все перед высказыванием мыслей.


    AA>Вкратце:

    А если в подробностях ? Может статью на эту тему, а то ощущается некая нехватка собранной и структурирванной информации на эту тему, причём на русском языке (помните главную идеологию RSDN — обширный портал для руско-говорящих программистов )

    Вопрос.
    Как-то в одной из веток (возможно даже в этой — сейчас уже не найду) проскакивало такое заявление: поскольку явных механизмов установки барьера памяти в C++ нет, то неявным является вызов обычной функции (вроде как компилятор должен обеспечить генерацию такого кода). То есть насколько я понял вызов функции (возможно специально оформленной — естественно inline функций это не касается ) гарантировано заставляет процессор перечитывать даные из памяти и тем самым решается проблема переупорядочивании комманд. Насколько это утверждение близко к действительности, из чего оно следует и можно ли его принять на вооружение, как гарантированное средство? Вызов каких именно функции приводит к таком поведению или всех кроме подставляемых?
    Компьютер сделает всё, что вы ему скажете, но это может сильно отличаться от того, что вы имели в виду.
    Re[5]: volatile у переменной класса
    От: MaximE Великобритания  
    Дата: 22.06.05 05:58
    Оценка:
    Здравствуйте, Mr. None, Вы писали:

    AA>>Вкратце:

    MN>А если в подробностях ? Может статью на эту тему, а то ощущается некая нехватка собранной и структурирванной информации на эту тему, причём на русском языке (помните главную идеологию RSDN — обширный портал для руско-говорящих программистов )

    В ветке были приведены все необходимые ссылки на док-цию Intel, Microsoft, POSIX, etc..
    Re[6]: volatile у переменной класса
    От: Mr. None Россия http://mrnone.blogspot.com
    Дата: 22.06.05 06:07
    Оценка:
    Здравствуйте, MaximE, Вы писали:

    ME>Здравствуйте, Mr. None, Вы писали:


    AA>>>Вкратце:

    MN>>А если в подробностях ? Может статью на эту тему, а то ощущается некая нехватка собранной и структурирванной информации на эту тему, причём на русском языке (помните главную идеологию RSDN — обширный портал для руско-говорящих программистов )

    ME>В ветке были приведены все необходимые ссылки на док-цию Intel, Microsoft, POSIX, etc..


    А где это ообщение... я его найти не могу — тогда мельком просмотрел, а сейчас хочется прочитать по подробнее...
    Компьютер сделает всё, что вы ему скажете, но это может сильно отличаться от того, что вы имели в виду.
    Re[7]: volatile у переменной класса
    От: MaximE Великобритания  
    Дата: 22.06.05 06:17
    Оценка:
    Mr. None wrote:

    []

    > ME>В ветке были приведены все необходимые ссылки на док-цию Intel, Microsoft, POSIX, etc..

    >
    > А где это ообщение... я его найти не могу — тогда мельком просмотрел, а сейчас хочется прочитать по подробнее...

    Боюсь, что тебе придется прочитать всю ветку со всеми ссылками.

    --
    Maxim Yegorushkin
    Posted via RSDN NNTP Server 1.9
    Re[2]: volatile: а можно примеры?
    От: mukos Голландия  
    Дата: 24.06.05 10:40
    Оценка:
    Здравствуйте, eao197, Вы писали:

    E>Добрый день всем.



    Я думаю так —
    что во всех вышеприводимых примерах в потоках использовались
    функции практически ничего не делающие поэтому естественно компилятор имел полное право
    забить переменную в регистр и читать ее только оттуда (без применения violatile)а втором потоке допустим
    писал значение в память поэтому происходило зацикливание процесса т.е. в данном конкретном
    случае имеет смысл указывать violatile (чтобы переменная каждый раз сливалась читалась из памяти) но я не вижу здесь смысла использовать обьекты
    синхронизации поскольку запись или чтение переменной если и не происходят за один такт
    то по крайней мере я не думаю что переключение контекста потока произойдет во время выполнения операциию.
    Я использую синхронизацию в основном где может идти чтение запись данных которые могут быть непрочитаны \недозаписаны
    между переключением контекста.
    Но в конкретных приложениях выполняются какие либо операции (я имею в виду не просто i++и в ходе их выполнения
    для освобождения регистра его все равно приходиться сливать в память хотя это видимо не 100% гарантия
    поэтому думаю что имеет смысл пользовать violatile хотя бы для очистки совести.....
    до прочтения этой ветки я не испльзовал violatile и не сталкивался с проблемами его не использования но теперь думаю буду
    Всегда хочется быть лучше
    Весь мир — Кремль, а люди в нем — агенты
    Re[3]: volatile: а можно примеры?
    От: Rakafon Украина http://rakafon.blogspot.com/
    Дата: 30.07.09 15:23
    Оценка:
    Здравствуйте, mukos, Вы писали:

    M>Я думаю так -

    M>до прочтения этой ветки я не испльзовал violatile и не сталкивался с проблемами его не использования но теперь думаю буду

    А я вот, во время проектирования приложений (в том числе и кроссплатформенных), всегда, следуя правилам хорошего тона, синхронизировал конкурентные данные с помощью соответствующих примитивов синхронизации (сперва самописных, реализованных через Crirical Section на винде и через pthreads на линуксе, потом — запользовал boost::recursive_mutex), но никогда volatile не пользовал, ибо мне не совсем было ясно на фига это делать, а теперь, после прочтения всей ветки, гарантированно никогда volatile не заюзаю, ибо понял, что юзать квалификатор volatile реально незачем!

    P.S.: ... да, и кстати, как там на счёт статьи? ... чтобы коллег просвещать не 25-страничным тредом на форуме, а лаконично изложенной грамотной статьёй с примерами сорцов! Кто нибудь из уважаемых <b>Alex Alexandrov</b>, <b>MaximE</b> или Александр Терехов, взялся за это благое дело?
    "Дайте мне возможность выпускать и контролировать деньги в государстве и – мне нет дела до того, кто пишет его законы." (c) Мейер Ансельм Ротшильд , банкир.
    volatile
     
    Подождите ...
    Wait...
    Пока на собственное сообщение не было ответов, его можно удалить.