2

I am having a question on the volatile usage. I typically try that all the variables shared across threads have the volatile keyword to ensure direct memory accesses, and of course protected with mutexes.

However, is volatile really needed if a variable is shared to ensure consistency?

I explain with an example:

Thread1: //(affects it behaviour with the variable)
mymutex.lock();
if(variable)
{
   ...
   variable = false;
}
mymutex.unlock();

Thread2:
mymutex.lock();
variable = true;
mymutex.unlock();

In the upper example, thread2 only writes, and thread1 reads/writes. Is it possible that the variable is cached and the threads do not read the new value? Even though the mutexes are properly set? Do I need volatile in this case?

I am asking this because instead of variable I have a std::vector, which cannot be volatile. And I am not 100% sure that this approach is safe without the volatile keyword.

Thanks.

EDITED: Reformulating the question properly.

DarkZeros
  • 8,235
  • 1
  • 26
  • 36
  • 6
    As long as your access to variables is protected by mutex - [you do not have to use `volatile`](http://stackoverflow.com/questions/11172922/does-stdmutex-create-a-fence) – Evgeny Panasyuk Oct 30 '13 at 14:18
  • So, if I derive your comment. Then all the variables accessed inside a mutex/semaphore/CriticalSection, are flushed and visible to other threads after the lock is released? – DarkZeros Oct 30 '13 at 14:25
  • @DarkZeros Exactly! That's how it works. – πάντα ῥεῖ Oct 30 '13 at 14:26
  • @DarkZeros Additionally you should use `std::lock_guard` – πάντα ῥεῖ Oct 30 '13 at 14:27
  • 1
    possible duplicate of [Is 'volatile' needed in this multi-threaded C++ code?](http://stackoverflow.com/questions/3612505/is-volatile-needed-in-this-multi-threaded-c-code) – doron Oct 30 '13 at 14:27
  • 1
    @DarkZeros If you release lock on one thread, and then trying to read that variable on another *without* locking mutex (suppose you have some other means to ensure the absence of races) then you should use some kind of [`fence`](http://en.wikipedia.org/wiki/Memory_barrier). In some environments `volatile` can be used to ensure atomic access, but - it is implementation-dependent, and you should prefer to use ready library with atomics and fences like [`Boost.Atomic`](http://www.boost.org/doc/libs/1_54_0/doc/html/atomic.html), or if you have `C++11` - then just use standard stuff. – Evgeny Panasyuk Oct 30 '13 at 14:31

2 Answers2

5

volatile in C++ is not meant for concurrency. It's about whether the compiler is allowed to optimize away reads from a variable or not. It is primarily used for things such as interfacing with hardware via memory mapping.

Unfortunately, this means that even if you do have volatile variables, the reads and writes may still access a thread-local store which is not synchronized. Also, an std::vector is not thread safe.

So, in either case, you need to synchronize, for example using a std::mutex (which you do mention). Now, if this is done, the variables which are protected by that mutexdo not need to be volatile. The mutex itself does the synchronization and protects against the type of issues you worry about.

Agentlien
  • 4,996
  • 1
  • 16
  • 27
  • 2
    Correct answer. I'd only like to emphasize which has been already said: "volatile" is not for thread synchronization. If anyone uses volatile for synchronizing threads, the chance that the code will still be incorrect is >90% but will be slower in addition. Ofc there are valid contexts to use volatile in threading, but very few, and usually when implementing low-level synchronization primitives (such as spinlocks). – ultimA Oct 30 '13 at 14:57
  • Thank you. I found a lot of answers saying "do not use volatile to share data". I obviously not going to share data with volatile only without a mutex. I always use a mutex for sharing. My question is "Is the data flushed without volatile?". This is clearly what I was looking for. – DarkZeros Oct 30 '13 at 15:29
  • @DarkZeros All you can ensure is that, if you use proper synchronisation, the effect will be as if the operations from the different threads were interleaved. How they get interleaved and when you see the value written by another thread is beyond your control. However, volatile does not change this, so adding it doesn't solve that problem. – Agentlien Oct 30 '13 at 15:41
  • A spot on answer. I haven't seen this explained so clearly, concisely and correctly before: `volatile` _does have an effect_ in the main, but in this situation it's a completely redundant effect. – Lightness Races in Orbit May 08 '15 at 14:26
0

Take a look at my answer here.

Bottom like, don't be clever are use volatile to try guarantee thread safety, use proper

Community
  • 1
  • 1
doron
  • 27,972
  • 12
  • 65
  • 103