문제

There are a number of related questions, but this question is arguably more specific.

Consider the following sample program, note that the bool is just an ordinary bool.

When I run it, it achieves the desired effect: after the user presses Enter, hello world will cease to print.

If I require only that bar2() eventually starts returning immediately after run is to false, is the logic below guaranteed to be safe by the standard?

#include <thread>
#include <mutex>
#include <unistd.h>


bool run = true;

void bar2() {
    // Is this check safe without a lock?
    if (!run) return;
    printf("hello world\n");
    fflush(stdout);
}
void bar() {
    while (true) {
        bar2();
        sleep(1);
    }
}

int main(){
    std::thread(bar).detach();
    getchar();
    run = false;
    // Prevent main from exiting.
    getchar();
}
도움이 되었습니까?

해결책

There is no guarantee by the standard that without synchronization or ordering guarantees given by e.g. std::atomic the other thread will ever see the write to run.

As a matter of fact the compiler would be perfectly fine to only check once that write is true and since the thread itself never writes to it cache the value without ever reloading it. Now practically speaking with all the c library calls going on the compiler generally cannot know that none of functions writes to run and under x86 you don't have to worry about not seeing updates from other processors to memory, so it will in practice work (and even under other architectures a context switch would probably resolve the problem).

But if you're talking purely from the standard's point of view? No guarantees whatsoever.

다른 팁

It is certainly the case that the standard makes no guarantees of how this code will behave. The testing and setting of the run variable are not properly sequenced. As a consequence, relying on the order of setting and testing constitutes undefined behaviour.

The question of what a "real world" compiler will actually do is less easy. There are several things a compiler could reasonably do which would cause this program to fail. It could:

  1. Detect the UB and institute its own implentation-specific course of action, which might work as you wanted, or not. At least if you test it, you will find out which.
  2. Make the assumption that UB has not occurred, and delete the if(!run) test from the program, since without the UB it can never have any effect.
  3. Observe that the run variable is never tested after it was set, and delete the run=false, since it can never have any effect. [This may involve assuming no UB.]

If it was my choice, I wouldn't rely on this code. I would use the capabilities provided by the standard and write conforming behaviour.

yes, it is completely safe. most processors have 32 bit pipelines.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top