2

I wrote a very simple code to reproduce my problem.

#include <iostream>
#include "tools.h"  //contains s_sleep()
#include <thread>
using namespace std;

void change( int *i)
{
        while (true)
        {
                *i = 4356;
        }
}

int main()
{
        int v=3;
        cout << v <<endl;
        thread t(change, &v);
        s_sleep(1); //sleep one second
        cout << v << endl;
        t.join();
}

The output is 3, and after a second 3 again. But when I change one line to

//while ( true )

I receive 3, and a second later 4356.

How can that be? Hope somebody can help.

JuliB
  • 73
  • 1
  • 7
  • 10
    Read up on what a data race is. Your program produces undefined behavior because of it. – nwp Jun 07 '17 at 12:01

2 Answers2

2

Please specify what compiler you are using. I am using Microsoft Visual C++ compiler, and with my visual studio, I see for both time, the output is 3 followed by 4356.

Here is the code I ran on my computer.

#include <ctime>
#include <thread>
#include <iostream>
using namespace std;
void change(int *i) {
    while (true) { // commented out this later, the result is same.
        *i = 4356;
    }
}

int main() {
clock_t tstart = clock();
    int v = 3;
    cout << v << endl;
    thread t(change, &v);
    while(double(clock() - tstart)/CLOCKS_PER_SEC < 3.0) { // Instead of your s_sleep
        int x = 1; // Just a dummy instruction
    }
    cout << v << endl;
    t.join();
    return 0;
}

The explanation to my result is that the thread "t" does not know anything about the variable "v". It just gets a pointer of type int and it edits the value at the pointers location directly to the memory. So, when the main(first) thread again accesses the variable "v", it simply reads the memory assigned to "v" and prints what it gets.

And also, what code is in the "tools.h"? Does it have anything to do with the variable "v".

If it doesn't, then it must be a compiler variance(Your compiler may be different than mine, maybe gcc or g++?). That means, your compiler must have cached(or something like that) the variable for faster access. And as in the current thread, the variable has not been changed, whenever it is accessed, compiler gives the old value(which the compiler sees as unchanged) of the variable. (I AM NOT SURE ABOUT THIS)

Rahat Zaman
  • 1,322
  • 14
  • 32
  • As said in the comment of the question: the program has undefined behavior, so if it works for your compiler doesn't mean much, it could even be different when compiling in a different configuration. There is cpu congestion and cache and other things involved which can cause different results when accessing data from different threads. Always use `std::atomic` or protect with `std::mutex` for this; they may be slower but they assure that what is written in one thread is reflected in the other.. – stefaanv Jun 07 '17 at 15:13
  • You are right. The simplest explanation is, the program has undefined behaviors because, sometimes the code inside the second thread is ran earlier than the first thread, and sometimes vice-versa. (As the both are being run parallel to each other.) – Rahat Zaman Jun 07 '17 at 15:36
  • 1
    You are right. I was using the GNU compiler suite, and the problem was the optimization. I disabled it, and now it works! Thank You! – JuliB Jun 07 '17 at 15:42
  • @JuliB: what you did shows that it doesn't work. It just seems to work. – stefaanv Jun 07 '17 at 15:47
-1

This might also be due to caching. You are first reading a variable frome one thread, then manipulating the variable from another thread and reading it again from the first thread. The compiler cannot know that it changed in the meantime. To safely do this "v" has to be declared volatile.

Tobi
  • 47
  • 4
  • 3
    For thread communication `std::atomic` should be used, not `volatile` – stefaanv Jun 07 '17 at 12:50
  • if you can use c++11... And I think volatile serves as a good explanation of what happens here. The author asked only "how can that be" – Tobi Jun 08 '17 at 13:44
  • We are middle 2017, so except for some deep embedded systems, C++11 should be considered C++. "To safely do this 'v' has to be declared volatile" means that you advice to use volatile. The problem with volatile is that it sometimes works but is likely to fail on multicore systems. It is a compiler feature but the CPU/cache knows nothing about it, see also https://stackoverflow.com/a/2485177/104774. Alas, the accepted answer (other compiler / no optimization) is worse. – stefaanv Jun 08 '17 at 14:19
  • C++11? Too bad indeed. I would suggest boost. – stefaanv Jun 08 '17 at 14:34
  • Sure, but even boost some of them didn't like. Should change client... Anyhow, I think that this here is indeed less a problem of concurrency than of compiler optimizations. After waiting for one second in the main thread, the change function should have completed at least one loop. But without the volatile (or atomic, of course) the compiler turns while(true) { *i = 4356; } into while(true); *i = 4356; and the keyword prevents optimization on that variable. – Tobi Jun 08 '17 at 14:49
  • The problem was about caching – JuliB Dec 30 '17 at 12:23