Thread safe access to shared data

Discussions on more advanced topics such as monolithic vs micro-kernels, transactional memory models, and paging vs segmentation should go here. Use this forum to expand and improve the wiki!
Post Reply
User avatar
AnishaKaul
Member
Member
Posts: 41
Joined: Thu Apr 19, 2012 12:29 am
Location: Gurgaon, India
Contact:

Thread safe access to shared data

Post by AnishaKaul »

From here: http://stackoverflow.com/a/2485177/462608
For thread-safe accesses to shared data, we need a guarantee that
the read/write actually happens (that the compiler won't just store the value in a register instead and defer updating main memory until much later)

that no reordering takes place. Assume that we use a volatile variable as a flag to indicate whether or not some data is ready to be read. In our code, we simply set the flag after preparing the data, so all looks fine. But what if the instructions are reordered so the flag is set first?
  • In which cases does compiler stores the value in a register and defers updating main memory? {with respect to the above quote}
  • What is the "re-ordering" that the code is talking about? In what cases does it happen? How does it help? Why would compiler do that? After all doesn't it have to execute the instructions in the given order?
http://500px.com/Anisha_Kaul/photos
User avatar
AnishaKaul
Member
Member
Posts: 41
Joined: Thu Apr 19, 2012 12:29 am
Location: Gurgaon, India
Contact:

Re: Thread safe access to shared data

Post by AnishaKaul »

berkus wrote:It's the CPU, not the compiler doing the reordering. Since the CPUs are out-of-order execution capable, especially on SMP there's a bit of options how memory accesses can be ordered.
Thanks, that was a helpful link. I'll study it.
Meanwhile I asked this on the other forum and got to know that contents of the registers aren't visible outside a processor. Volatile keyword is used when we want to tell the compiler that this variable will be modified by some external source. So, when during multithreading on multiple processors at the same time, we may want a thread from an another processor to edit our variable, so we make it volatile by asking the compiler not to store it in the registers.
AnishaKaul wrote:Let me google "memory barriers" for you.
Thanks for the key word. I'll Google it and get back if I don't understand something.
http://500px.com/Anisha_Kaul/photos
User avatar
Combuster
Member
Member
Posts: 9301
Joined: Wed Oct 18, 2006 3:45 am
Libera.chat IRC: [com]buster
Location: On the balcony, where I can actually keep 1½m distance
Contact:

Re: Thread safe access to shared data

Post by Combuster »

berkus wrote:
AnishaKaul wrote:In which cases does compiler stores the value in a register and defers updating main memory?
It's the CPU, not the compiler doing the reordering.
Actually, the compiler is happy to replace

Code: Select all

bool locked = false;

void util()
{
    locked = true;
    /* access some stuff */
    locked = false;
}
with

Code: Select all

bool locked = false;

void util()
{
    /* access some stuff */
    locked = false;
}
If the rest of the function does not have any dependencies on "locked". After all why would you do something if it's not going to get used anyway? The Volatile keyword fixes that.

However, for actual mutual exclusion tasks you're usually better off using the lock bt* (for test-and-set), lock xadd (fetch-and-increment) or lock cmpxchg* (compare-and-swap) opcodes because they are designed for just that.
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]
User avatar
Creature
Member
Member
Posts: 548
Joined: Sat Dec 27, 2008 2:34 pm
Location: Belgium

Re: Thread safe access to shared data

Post by Creature »

I just wanted to add that when using C/C++, using volatile should be enough to instruct the compiler to not optimize away any reads/writes to the variable nor cache it in the register. It also should not be moved around (at least according to the VC++ compiler documentation). IIRC, things are different when using inline assembly (at least in GCC):

Code: Select all

// Mostly plug from the wiki.
__asm__("cli" : : : ); // GCC may optimize away or move around.
__asm__ __volatile__("cli": : : ); // GCC may not optimize away, but may still move around.
__asm__ __volatile__("cli": : : "memory"); // GCC may not optimize away and may not move around.
To make things even more complicated, according to some docs, __asm__ __volatile__ should be enough to instruct the compiler to also not move the instruction around. Take a look at the wiki and also the forum thread linked at the bottom.

If this is indeed the case and the instruction may still be moved when specifying __volatile__ and not specifying "memory" in the clobber list, forgetting to add this could lead to serious issues during optimization (particularly when CLI and STI instructions are used e.g. to prevent context switches and where their order is very important).
When the chance of succeeding is 99%, there is still a 50% chance of that success happening.
gerryg400
Member
Member
Posts: 1801
Joined: Thu Mar 25, 2010 11:26 pm
Location: Melbourne, Australia

Re: Thread safe access to shared data

Post by gerryg400 »

If a trainstation is where trains stop, what is a workstation ?
User avatar
Creature
Member
Member
Posts: 548
Joined: Sat Dec 27, 2008 2:34 pm
Location: Belgium

Re: Thread safe access to shared data

Post by Creature »

gerryg400 wrote:Creature, check out this thread

http://forum.osdev.org/viewtopic.php?f=11&t=24168
Yes, this was the thread I was referring to, thanks for placing it here. There should also be a link in the wiki at the page I linked at the bottom. I haven't been OSDevving for some time, but I remember having the exact same problem and realized after reading the thread that that was probably my mistake too.
When the chance of succeeding is 99%, there is still a 50% chance of that success happening.
Post Reply