Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Do I need to protect this variable with a lock?

so I have a boolean type in C++ on a multiprocessor machine. The variable starts out life as true, and then there are a few threads, any one or more of which might write it to be false.

At the same time, these threads may also read this variable to check its state. I don't care if reading this variable is synchronized with any of the writes, they each happen at different places in the code, and it doesn't matter if it comes before or after any particular write. Now, do I need a lock for this boolean?

The only way I would need a lock is if at the very low level, memory can get corrupted by two competing writes. If, for example, an assembly instruction on processor A is writing 0 to the byte that represents the boolean at the same time as processor B is doing the same... and instead of having written 0, the memory ends up with value 22 or something. That could mess something up.

So, generally, if proc A is writing 3 to a memory location, while proc B is writing 7, with no synchronization, am I guaranteed to end up with at least either 3 or 7? Or is it that easy to break memory?

Edit:

Thanks for the comments guys. Some more info: There is synchronization in the program of course. To summarize, the flag in question is telling if a certain memory pool is "dirty" (needs to be compacted). Any thread can hence decide to set this flag to false (meaning pool is dirty). For example, freeing memory from the pool makes it dirty. Any thread can then also read this flag and set another flag to signal that a clean-up is needed -- this check is done when memory is allocated from the pool, the clean-up is signaled if we're low on memory. Somewhere in my master critical section between iterations, where each thread goes to look for more data to process, I will have the threads check this second flag, and do something appropriate to make sure that: all other theads finish their current iteration, one thread cleans up the memory, sets the first flag back to true (as in pool is not dirty), sets the second flag back to false, and then releases all the threads again.

So I don't think I need a lock because: a lock would ensure that a write doesn't happen at the same time as another write or a read. But who cares, as long as the hardware doesn't fail me, the worst-case-scenario is that the read happens randomly before or after the write -- this is the same thing that would happen if I protected it with a lock, just then we'd really be sure it came before or after...

I think the same argument applies to the second flag I mentioned above.

like image 237
Scott Avatar asked Jul 12 '10 00:07

Scott


People also ask

Do you need a lock for a condition variable?

A condition variable is more primitive, only providing the signal. At least in C++, there is no need to protect the signalling with a lock. In fact, depending on how the implementation handles the scheduling of the waiting thread, it might be harmful for performance to perform the signalling inside the lock.

How to lock variable Python?

A variable can be locked using a mutual exclusion (mutex) lock.

Why do we need locks?

Locks are used to guard a shared data variable, like the account balance shown here. If all accesses to a data variable are guarded (surrounded by a synchronized block) by the same lock object, then those accesses will be guaranteed to be atomic — uninterrupted by other threads.

What is a lock in a thread?

The LOCK THREAD statement ensures that no other thread executes. This condition remains in effect until the thread is unlocked (with UNLOCK THREAD) or the thread terminates.


3 Answers

On most commodity hardware a single word reads/writes are atomic, so no, two (or more) competing writes (and reads) to the same memory location are not going to corrupt the value. What is important here is cache coherence between CPUs.

Again, on commodity hardware you might get away with just marking that single boolean variable volatile (which has been declared useless for concurrent programming btw) to prevent compiler from optimizing it out into a register, but only if you really don't care about the order of writes.

Let me re-iterate this with a check-list:

  • Are you ready do lose some updates to that boolean?
  • Are you sure no other memory updates that come before the boolean flip in the source code but might get reordered after that flip are going to mess things up?
  • Are you sure you don't care about order of events in your application?

If you have three strong "yes" answers, you might get away with not protecting that flag. Still consider inserting acquire memory barrier before reading the variable, and release memory barrier before writing it. My suggestion though would be to re-think the design, and lay out clear synchronous inter-thread communications and event sequencing.

Hope this helps.

like image 169
Nikolai Fetissov Avatar answered Oct 12 '22 11:10

Nikolai Fetissov


If only you're checking the state of the variable and setting it to false in one direction ever, there's not much to worry about except that some of the threads may be a little late to see the variable is already set to false. (this may be overcome to some degree by the use of 'volatile' keyword.) Then two threads may set it to false, which is no problem since the variable is set to a single value in one direction. Let's say boolean write to the memory location is not guaranteed to be atomic, what's the harm? The final value they both will write is the same.

Still, you would have to use a method of locking if:

  • Value setting is not one-direction only: you set it to false, then back to true, then false again, etc.
  • You take some dependent action on the information which thread had set the value to false. Because there obviously may be two winners.
like image 43
Gorkem Pacaci Avatar answered Oct 12 '22 09:10

Gorkem Pacaci


It's an easy way to break things. With a boolean, you may be ok most of the time, but are provided no guarantees.

You have two options: use a mutex (lock), or use atomic primitives. Atomic primitives will utilize hardware instructions to do the test and set operations in a thread-safe fashion without requiring an actual mutex and are a lighter-weight solution. The GNU compiler provides access to atomic operations via architecture-specific extensions. There are also portable atomic operation libraries floating around; the Glib C library provides atomic operations that fall back to using a mutex if atomic primitives are not available, although it is a fairly heavy library with many other features as well.

There is the Boost.Atomic library which abstracts atomic operations for C++; based on its name, it looks like it is aiming to be incorporated into the Boost C++ library collection but hasn't yet made it.

like image 34
Michael Ekstrand Avatar answered Oct 12 '22 11:10

Michael Ekstrand