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
     
    Подождите ...
    Wait...
    Пока на собственное сообщение не было ответов, его можно удалить.