Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is this rule about volatile usage strict?

I've seen this sentence:

the general rule is, if you have variables of primitive type that must be shared among multiple threads, declare those variables volatile

from this article, and this sentence:

In general, any data that may be undated asynchronously should be declared to be volatile.

from this page, now considering this introduced rule I'd like to know could you bring an example of a case where despite existence of asynchronous access to a data declaring that data volatile has no use in practice or there's no such exceptional case and the rule is strict.

like image 472
Pooria Avatar asked Nov 27 '22 06:11

Pooria


2 Answers

I remember when that article was published and I remember the endless discussions that then followed on comp.lang.c++.moderated.

IIRC, Andrei hijacks the volatile keyword to use it to discriminate between different function overloads. (See this article by Scott Meyers for another such an idea.) What he does is brilliant, in that it allows the compiler to catch you if you mess up protected and unprotected access to objects (very much like the compiler catches you should you try to modify a constant). But besides the fact that it helps you, it has nothing to do with actually protecting concurrent access to objects.

The problem is only that 90% of the people have one glance at the article and all they see is volatile and "threads" in the same article. Depending on their knowledge, they then either draw the wrong conclusion that volatile is good for threads (you seem to have done so) or they yell at him for leading others to draw the wrong conclusions.
Very few people seem to be able to actually read the article thoroughly and understand what he really does.

like image 180
2 revs Avatar answered Dec 04 '22 03:12

2 revs


I can't speak for the actual asynchronous access scenario, since I'm not too good at multithreading, but what the volatile modifier does is tell the compiler:

"Listen, this may change at any time, so don't cache it or put it in a register or do anything crazy like that, okay?"

It does not protect against asynchronous writes, it simply disables optimizations that are invalid if the variable can be changed by external forces.

Edit: As a potential example, one that doesn't involve multithreading (but, does involve exceptionally convoluted code ;), here's a case where volatile is important:

volatile bool keepRunning = true;
void Stuff() {
    int notAPointer = 0;

    notAPointer = (int)(&keepRunning); //Don't do this! Especially on 64-bit processors!

    while(keepRunning) {
        *(bool*)(notAPointer) = false;
    }

    printf("The loop terminated!");
}

Without that volatile modifier, the compiler might go "Hey, keepRunning is never modified, so I don't even need to generate code that checks it!", when in reality we're simply modifying it in secret.

(In reality, this would probably still work on a non-optimized build. And, it might also still work if the compiler is smart and notices the pointer being taken. But, the principle is the same)

like image 22
Mike Caron Avatar answered Dec 04 '22 02:12

Mike Caron