Is this rule about volatile usage strict?

2020-02-07 03:45发布

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.

8条回答
地球回转人心会变
2楼-- · 2020-02-07 03:53

I would say that in theory those rules are absolutely right, and volatile is needed every time when a variable is accessed by 2 threads. (Even when using mutexes, cause they don't prevent compiler optimizations.) But in practice compilers are good enough at recognizing situations where a variable might be modified outside a particular function so that its value shouldn't be cached in registers. In most cases volatile is not necessary.

I once did some testing in MSVC by inspecting the assembler output for different situations, and all it took to prevent a variable from being cached was to have another function writing to the same variable or taking its address. Global variables were never optimized unless "whole program optimization" was turned on (so the compiler can be sure the variable is not modified in other translation units).

查看更多
ゆ 、 Hurt°
3楼-- · 2020-02-07 04:01

Before you take the article you linked to first too seriously, you might want to read another. In a later posting on Usenet, Andrei later admitted that parts of the original article were just plain wrong, and pointed to this one as giving a more realistic view of things (though note that the link he gives to it there seems to have gone stale).

查看更多
Deceive 欺骗
4楼-- · 2020-02-07 04:07

To follow up on Mike's answer, it's useful in cases like this (global variables used to avoid complexity for this example):

static volatile bool thread_running = true;

static void thread_body() {
    while (thread_running) {
        // ...
    }
}

static void abort_thread() {
    thread_running = false;
}

Depending on how complex thread_body is, the compiler may elect to cache the value of thread_running in a register when the thread begins running, which means it will never notice if the value changes to false. volatile forces the compiler to emit code that will check the actual thread_running variable on every loop.

查看更多
男人必须洒脱
5楼-- · 2020-02-07 04:12

Likewise, the C++ standard does not specify how volatile should work, you have to look at what a particular compiler does for a particular platform. Also volatile is a bit subtle and what it does, depends on the compiler and the memory model of the target platform. Locks are way more intuitive to use.

查看更多
神经病院院长
6楼-- · 2020-02-07 04:14

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)

查看更多
太酷不给撩
7楼-- · 2020-02-07 04:16

Read this. Volatile has nothing to do with multi-threading.

查看更多
登录 后发表回答