Regarding this question Is there cases where a 32-bit variable could not been properly-aligned and the answers provided, can I assume I can swap addresses without any side effect when working under the windows platform?
For instance:
struct Foo
{
// whatever Foo can hold
};
struct Bar
{
void buildFoo()
{
auto tmp = new Foo;
// do some stuff on tmp, or not
foo = tmp;
}
Foo* foo;
};
Now, what are the consequences of having some threads using foo
through an instance of Bar
, and other threads invoking Bar::buildFoo()
?
Depending on the compiler and the platform, the pointer assignment may or may not be atomic.
Atomic operations are intended to allow access to shared data without extra protection (mutex, rwlock, …). This may improve: ● single thread performance ● scalability ● overall system performance.
It is not atomic. Atomic operations are not cheap and 99% of the time you do not need the atomicity. There are (IIRC) some other means to get atomic operations but std::swap() is not one of them.
An atomic operation is a read-modify-write sequence that is performed without interference from another requester. Like exclusive accesses in AXI, Atomic Transactions allow a requester to modify data in a particular region of memory, while ensuring that writes from other requestors do not corrupt the data.
The C++ Standard
No, concurrently modifying/accessing raw2 pointers are not guaranteed to be an atomic operation in c++.
The C++ standard says that a data race is present if one thread modifies a memory location and another one modifies/access the same memory location, and if such a data race is present the program suffers from undefined behavior.
[intro.multithread]
4)
Two expressions evaluations conflict if one of them modifies a memory location (1.7) and the other one accesses or modifies the same memory location.
...
21)
The execution of a program contains a data race if it contains two conflicting actions in different threads, at least one of which is not atomic, and neither happens before the other. Any such dat race results in undefined behavior.
1.raw is in not being wrapped in std::atomic<Foo*>
, or equivalent.
Implementation specific behaviour (windows 32/64bit)
Under windows it's guaranteed that read/writes to properly-aligned 32-bit
variables are always atomic, as is stated by the article linked by the question/answer you have referenced earlier.
Access to properly aligned 64-bit
variables are also atomic on 64-bit
windows.
Interlocked Variable Access - http://msdn.microsoft.com/en-us/library/ms684122%28VS.85%29.aspx
Simple reads and writes to properly-aligned 32-bit variables are atomic operations. In other words, you will not end up with only one portion of the variable updated; all bits are updated in an atomic fashion.
However, access is not guaranteed to be synchronized. If two threads are reading and writing from the same variable, you cannot determine if one thread will perform its read operation before the other performs its write operation.
What does this mean?
The standard says one thing, while the documentation from microsoft says another.. which are we to trust and work with? It certainly depends on what we are doing.
If we are developing soley for the windows platform we could read up on what the used compiler guarantees in regards of code generation and go from there, but if we want to write code that might be compiled and run under different platforms the only thing to properly trust is the standard.
So when working under windows I can safely swap 32-bit variables?
If you by "swapping" mean an operation such as what is written in the snippet below the answer is No, but if you mean "to assign" the answer is Yes.
void swap (int& a, int& b) {
int tmp = a;
a = b;
b = tmp;
}
int main () {
int x = 1;
int y = 2;
swap (x, y);
}
Nothing in the above snippet (or the previously mentioned documentation) says that this will be an atomic operation, and when looking at the implementation of our swap
we easily see that the operations aren't synchronized properly.
Reading/writing a single 32-bit variable is safe under windows, but in the above there's nothing that guarantees that both x
and y
doesn't have the value 2
when we are in the middle of our swap
.
It is, however, guaranteed that x
never will consist of 50% of the bytes in the previous x
and 50% of the bytes in y
, or similar.. the individiual writes are atomic.
Setting foo
may be atomic, but it's implementation specific. The reason for this is that most platforms write to a word sized address in a single instruction, and this is an atomic operation. However, there's no requirement that your platform store its pointers in a word sized location, although it'd be rare not to.
You also need to take into account instruction reordering and the fact that other threads may not see the write to foo
for some time the location of the pointer may be held in the processor cache and not flushed to memory.
Given all this you're better of using the std::atomic
types, or if you don't have access to C++11 then there should be some sort of interlocked read/write functions available.
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