Where all to use volatile keyword in C

前端 未结 5 1632
余生分开走
余生分开走 2021-01-20 04:37

I know volatile keyword prevents compiler from optimizing a variable and read it from memory whenever it is read. Apart from memory mapped registers, what are all the situat

相关标签:
5条回答
  • 2021-01-20 05:09

    Apart from memory mapped registers, what are all the situations where we need to use volatile?

    If

    1. execution is purely sequential (no threads and no signals delivered asynchronously);
    2. you don't use longjmp;
    3. you don't need to be able to debug a program compiled with optimizations;
    4. you don't use constructs with vaguely specified semantics like floating point operations;
    5. you don't do useless computations (computations where the result is ignored) as in a benchmark loop;
    6. you don't do timings of any pure computations, that is anything that isn't I/O based (I/O based such as timings of accesses of network requests, external database accesses)

    then you probably have no need for volatile.

    0 讨论(0)
  • 2021-01-20 05:10

    In neither of your examples is volatile necessary.

    volatile is necessary:

    1. anywhere a variable may be changed outside of the control of a single thread of execution,
    2. anywhere the variable access is required to occur even when it semantically has no effect.

    Case 1 includes:

    • memory mapped I/O registers,
    • memory used for DMA transfers,
    • memory shared between interrupt and/or thread contexts,
    • memory shared between independent processors (such as dual port RAM)

    Case 2 includes:

    • loop counters used for empty delay loops, where the entire loop may otherwise be optimised away completely and take no time,
    • Variables written to but never read for observation in a debugger.

    The above examples may not be exhaustive, but it is the semantics of volatile that are key; the language only has to perform an explicit access as indicated by the source code.

    0 讨论(0)
  • 2021-01-20 05:10

    Besides extensions such as memory mapped devices, in standard C volatile has two use cases: interaction with signal handlers and modification of objects across usage of setjmp/longjmp. Both are case were there is unusual flow of control that an optimizer may not be aware of.

    0 讨论(0)
  • 2021-01-20 05:14

    In C microcontroller applications using interrupts, the volatile keyword is essential in making sure that a value set in an interrupt is saved properly in the interrupt and later has the correct value in the main processing loop. Failure to use volatile is perhaps the single biggest reason that timer-based interrupts or ADC (analog-digital conversion) based interrupts for example will have a corrupted value when flow of control resumes after the processor state is returned post-interrupt. A canonical template from Atmel and GCC:

    volatile uint8_t flag = 0;
    
    ISR(TIMER_whatever_interrupt)
    {
        flag = 1;
    }
    
    while(1) // main loop
    {
        if (flag == 1)
        {
            <do something>
            flag = 0;
        }
    }
    

    Without the volatile it's guaranteed to not work as expected.

    0 讨论(0)
  • 2021-01-20 05:29

    memory mapped I/O is the only generic use of volatile in C. *)

    With POSIX signals, a volatile can also be used together with the type sig_atomic_t like this:

    volatile sig_atomic_t signal_occured = 0;
    

    Neither of your scenarios should require volatile at all. If all you're interested in is a guarantee that the value is updated between different compilation units, see tofro's comment, extern already guarantees that. Particularly, volatile is not the correct tool for thread synchronization in C. It would only introduce bugs, because, as you state it, it does require actual read and write accesses to the variable, but it does not enforce their proper ordering with respect to threads (it's missing memory barriers, google for details).

    Note that this is different from some other languages where volatile is designed to work between threads.

    In an embedded system, volatile might be good enough for communicating between an ISR (interrupt service routine) and the main program, when combined with a data type that's read/written atomically, just like sig_atomic_t for POSIX signals. Consult the documentation of your compiler for that.


    *) The C standard mentions this, along with the use-case of "asynchronously interrupting functions", only in a footnote, because memory-mapped I/O is outside the scope of the language. The language just defines the semantics of volatile in a way that make it suitable for memory-mapped I/O.

    0 讨论(0)
提交回复
热议问题