I'm experimenting with C++0x support and there is a problem, that I guess shouldn't be there. Either I don't understand the subject or gcc has a bug.
I have the following code, initially x
and y
are equal. Thread 1 always increments x
first and then increments y
. Both are atomic integer values, so there is no problem with the increment at all. Thread 2 is checking whether the x
is less than y
and displays an error message if so.
This code fails sometimes, but why? The issue here is probably memory reordering, but all atomic operations are sequentially consistent by default and I didn't explicitly relax of those any operations. I'm compiling this code on x86, which as far as I know shouldn't have any ordering issues. Can you please explain what the problem is?
#include <iostream>
#include <atomic>
#include <thread>
std::atomic_int x;
std::atomic_int y;
void f1()
{
while (true)
{
++x;
++y;
}
}
void f2()
{
while (true)
{
if (x < y)
{
std::cout << "error" << std::endl;
}
}
}
int main()
{
x = 0;
y = 0;
std::thread t1(f1);
std::thread t2(f2);
t1.join();
t2.join();
}
The result can be viewed here.
There is a problem with the comparison:
x < y
The order of evaluation of subexpressions (in this case, of x
and y
) is unspecified, so y
may be evaluated before x
or x
may be evaluated before y
.
If x
is read first, you have a problem:
x = 0; y = 0;
t2 reads x (value = 0);
t1 increments x; x = 1;
t1 increments y; y = 1;
t2 reads y (value = 1);
t2 compares x < y as 0 < 1; test succeeds!
If you explicitly ensure that y
is read first, you can avoid the problem:
int yval = y;
int xval = x;
if (xval < yval) { /* ... */ }
The problem could be in your test:
if (x < y)
the thread could evaluate x
and not get around to evaluating y
until much later.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With