-1

I know some basics of 'volatile' but still I want to make it clear :)

If some variables in the memory are going to be modified by hardware, I know we need to use 'volatile' to protect it. However, my question is that:

  1. If the variables are going to be modified by another function in the same file;
  2. If the variables are going to be modified by another function in the same project (in different files, the codes may belong to the same thread of different threads).

Do you need to use 'volatile'?

Thanks,

ikh
  • 10,119
  • 1
  • 31
  • 70
Hao Shen
  • 2,605
  • 3
  • 37
  • 68

3 Answers3

3

In C, the volatile keyword instructs the compiler to make no assumptions and no "corner cutting" and just do all the work. This means the variable will always be read and written from memory instead of kept in registers. The compiler will also ignore everything the local context may imply for a variable, and abstain from doing certain optimizations.

It doesn't really matter which file or which function, as long as there is a possibility for the variable value to change from more than one point in the program (or even another process or other hardware mechanism), it should be marked as volatile, so that the correct value is retrieved from its actual location instead of using an assumed value or a cached copy from a register or being optimized away altogether.

Also keep in mind operations on volatile variables are not atomic. You should use atomics in multithreaded scenarios.

In short - volatile is mostly used in low level hardware operations, usually when something else besides your code might change a variable, it should barely, if at all, be used in application development. It is intended for micro-controller/hardware driver use primarily.

dtech
  • 47,916
  • 17
  • 112
  • 190
  • I do not quite undersand what you said. Many variables are going to be changed "from more than one point in the program"(for example, global variables) but many of them do not need to be marked as 'volatile'. – Hao Shen Jun 27 '14 at 23:57
  • The compiler will by default try to limit memory access as much as possible, which means a normal variable will be cached in a register, used and modified from that register and its value will be updated in mem when the function is completed. So the intermediate changes will not be reflected in the actual location of that variable in memory. That means if another function accesses the variable, it will access possibly an outdated copy from the memory. If the variable is volatile every operation will be done to the actual memory location, and accessing it from another point will be up-to-date. – dtech Jun 28 '14 at 00:01
  • In the case of globals the compiler can perform static analysis and use the right access. `volatile` instructs the compiler to not make any assumptions for cases it might not be aware of or not entirely clear on during compile time As others noted, you should typically not have to use `volatile` at all unless you are doing memory mapping, working with hardware interrupts and other advanced stuff. – dtech Jun 28 '14 at 00:09
  • Thanks a lot for your answer. So let's not assume some location in the memory will be changed by hardware. Let's just suppose all changes come from software(changed in different threads, changed in interrupt handler). In that case, according to your words, the complier should have full knowledge whether the variable will be changed at some other places or not. In that case, there is no situition when we need to use volatile. Feel confused.... – Hao Shen Jun 28 '14 at 06:36
  • 2
    @HaoShen - it most of the cases that is true. Or very rare occasions, the compiler might not be able to analyze deep enough and do some optimization that will not reflect side effects, which will lead to a bug you can then solve by marking the variable as volatile, but this is extremely rare. In 99.99% of the times you should not have to use volatile and just use mutexes to prevent race conditions. Note that interrupt handlers might actually require volatile, but it really depends on the use scenario and whether there is chance of a change from outside the program or one that it can't predict. – dtech Jun 28 '14 at 09:17
2

The use of volatile tells the compiler to not try and cache (in hopes of optimizing access to) the variable it declares. This includes instances of both hardware-modified memory and multi-threaded access to the same memory.

Although in case of multi-threading I'd suggest you look into using mutexes (or other available synchronization tools)

YePhIcK
  • 5,816
  • 2
  • 27
  • 52
  • So you mean in my situation 2, if the codes belong to the same thread, we do not need to use 'volatile' while if they belong to different threads we need to use 'volatile'? No matter whether the codes are in the same file or not? – Hao Shen Jun 27 '14 at 23:45
  • 1
    Whether the code is in the same file or not doesn't matter as much as which **thread** is executing the code. But, as I mentioned in the answer - the use of `volatile` is not an adequate mechanism of insuring a proper access to a block of memory in a multi-threaded environment – YePhIcK Jun 27 '14 at 23:47
  • Thanks. I see. So if we do not consider lock, your answer to my question is 'Yes'? – Hao Shen Jun 28 '14 at 00:00
  • I'd say that unless you are in device drivers' business you should (almost?) never have a need for a `volatile` in your code :) – YePhIcK Jun 28 '14 at 00:01
  • 1
    `volatile` does a lot more beyond "not trying to cache". There are plenty of things that the compiler is not **allowed** to do and others that it **must** do. For example, a read or write to a `volatile` variable can never be eliminated, as the compiler must assume it has side-effects. – Nik Bougalis Jun 28 '14 at 00:14
  • @YePhIcK Hi,thanks a lot for your answer. But actually I still feel very confused. Do you mind just giving me the answer 'yes' or 'no' for my first question?? I am now doing some hardware programming. Let's not consider something will be changed by ASIC. I just want to know the situation when some variables will be changed by software in the same project which might belong to the same or different threads. – Hao Shen Jun 28 '14 at 06:21
0

volatile is not widely-used, but there are a few practical examples. I'll show you one.

At first, look at this.

#include <stdio.h>
#include <threads.h> // C11 threading library

int i = 0;

int noticer_thread(void *arg)
{
    while (getchar() == 'a') // suppose something happened!
        i = 1;
    return 0;
}

int main()
{
    thrd_t thrd;
    int res;

    thread_create(&thrd, noticer_thread, NULL);

    while (i != 1) { /* wait... */ }
    printf("something happened!\n");

    thrd_join(thrd, &res);
}

(I've just tried C11 threading library - just practice ^o^)

Can you notice something wrong? Compiler doesn't know i will be changed by another thread, so the while loop of main can be optimized, like this -

register int EAX = i;
while (EAX != 1) { ...

Therefere, i should be volatile.

volatile int i = 0;

So, why is it practical example? In fact, I faced this kind of bug on my os-development. Suppose noticer_thread is interrupt handler, and main is kernel thread. noticer_thread set the flag which informs main of interrupt, but main couldn't know it without volatile!

ikh
  • 10,119
  • 1
  • 31
  • 70
  • So in other words,in the same C project, if the variable is going to be modified by the codes of another thread or codes in ISR, we need 'volatile'. However, if the variable is only going to be modified by another function in the same thread, we do not need 'volatile'?? That's not very reasonable to me. How can the complier know whether some codes belong to the same thread or not when the codes embedded with each other deeply. – Hao Shen Jun 28 '14 at 06:30
  • 1
    @HaoShen Well, compiler assumes all *possible* variables can be modified. Suppose doing `noticer_thread(NULL);` rather than `thrd_create(`, and suppose there's another global variable `j`. After `noticer_thread` returns, both `i` and `j` are assumed to be changed, even if `j` has never changed. But `thrd` and `res`, which are local variables, cannot be changed, so compiler knows these local variables cannot be changed. – ikh Jun 28 '14 at 09:41
  • @HaoShen However, if compiler uses **link time optimization**, the compiler (or linker?) knows behaviors of all functions, so it can know which variable is modified. – ikh Jun 28 '14 at 09:42
  • Your example implies that no other synchronisation would be necessary, to protect the variable `i` against concurrent access, which is not the case. -1 – alk Jun 29 '14 at 10:49
  • @alk yes, it requires synchronization, but that's not my point. Remember it's an answer related to `volatile` – ikh Jun 30 '14 at 13:19
  • You example is incomplete in terms of providing valid code. @ihk Even more if `i` were protected ` volatile` wouldn't be needed at all anymore. As the protection does everything to have the proper value stored/updated in `i` at the right time. To cut it short `volatile` is not ment to protect variables against concurrent access. – alk Jun 30 '14 at 13:25