I am writing this post in reference to Atomic store. Structures
@Peter Cordes said:
What does it mean to lock? Especially, I know that lock is a prefix that ensures about atomicity of "prefixed" instruction.
Lock as in spinlock / mutex, not lock prefix. The lock prefix only ever works on read-modify-write instructions; there is no lock mov [mem], eax to do an atomic unaligned store or something. locked bus cycles are always read-modify-write, as documented by Intel in the docs for cmpxchg. So a lock mov store would also generate a load, which has different semantics if you use it on memory-mapped I/O. (A read can trigger side effects).
Ok, so I understand it well. But, I cannot understand why it is copied (stored) atomically. It could be a spinlock instead of a mutex, but the situation is the same. A critical section is safe, I agree. But there is no certainty about atomic execution of that.
I add an example to explain what I mean:
struct S{int a, b, c, d, e;};
std::mutex mut; // global
S s = {0}; // global
//From what I understand atomic store could look like:
store(const S& src){
mut.lock();
S* dst = this->getPointerOfRawStructure(); // pseudocode
dst->a = src.a;
dst->b = src.b;
dst->c = src.c;
dst->d = src.d;
dst->e = src.e;
// I know that we can copy it in a better (faster) way.
mut.unlock();
});
And now, let thread1 do:
std::atomic<S> as;
as.store(s);
Now, mutex is free, so thread1 succesfully calls store.
Let thread2 do something like;
S* ptr = &s; // address of global variable s declared before.
int ee = s->e;
And, let assume that thread1
executed
dst->a = src.a;
dst->b = src.b;
dst->c = src.c;
And now thread2
executed:
int ee = s->e;
Thread2 sees old value of s->e
though as.store()
was started firstly and it should be executed in atomic way. ( The another thread cannot see a half-written variable, actually it sees).
So, I don't still understand how atomicity is ensured with lock (spinlocks/mutex).