5

In Java, sometimes when accessing the same variable from different threads, each thread will create its own copy of the variable, and so if I set the value of the variable in one thread to 10 and then I tried to read the value of this variable from another thread, I will not get 10 (because the second thread is reading from another copy of the variable!).

To fix this problem in Java, all I had to do is to use the keyword volatile, for example:

volatile int i = 123;

Does this problem also exists in C++? If so, how can I fix it?

Note: I am using Visual C++ 2010.

DJClayworth
  • 24,627
  • 8
  • 50
  • 71
paul
  • 515
  • 4
  • 14
  • 1
    the simplest approach is std::atomic. – Sneftel Jun 17 '15 at 13:22
  • 1
    `std::atomic` is not available in VC2010. `boost::atomic` is an option. – Bathsheba Jun 17 '15 at 13:25
  • 3
    Please read what `volatile` is (in Java). It seems you´re overestimating what it can do. And no, without `volatile` it is not "one copy per thread". – deviantfan Jun 17 '15 at 13:27
  • @deviantfan I think the OP is just talking about the compiler caching a value in register, which is technically "creating a copy'. Not the best way of thinking about it. – DJClayworth Jun 17 '15 at 13:29
  • @DJClayworth Yes, this is what I meant. – paul Jun 17 '15 at 13:30
  • 1
    @DJClayworth Maybe that´s what the OP is thinking, maybe not, that´s why I wrote it in the first place (that he should read something more about it) – deviantfan Jun 17 '15 at 13:30
  • 2
    Well, the threadcopy problem seems solved, but still: Read about volatile in Java. It´s *not* a perfect solution for thread safety in any and every situation. And C++ volatile is even less. – deviantfan Jun 17 '15 at 13:32
  • http://stackoverflow.com/questions/6319146/c11-introduced-a-standardized-memory-model-what-does-it-mean-and-how-is-it-g – Solomon Slow Jun 17 '15 at 17:42

1 Answers1

5

Yes, the same problem exists in C++. But since C already introduce the keyword volatile with a different meaning (not related to threads), and C++ used they keyword in the same way, you can't use volatile in C++ like you can in Java.

Instead, you're probably better off using std::atomic<T> (or boost::). It's not always the most efficient alternative, but it's simple. If this turns out to be a bottleneck, you can relax the std::memory_order used by std::atomic.

Having said that about standard C++, MSVC++ as an extension does guarantee that multiple threads can access a shared volatile variable. IIRC, all threads will eventually see the same value, and no threads will travel back in time. (That is to say, if 0 and 1 are written to a variable sequentially, no thread will ever see the sequence 1,0)

MSalters
  • 159,923
  • 8
  • 140
  • 320
  • Isn't `std::atomic` only available in C++11? – paul Jun 17 '15 at 14:59
  • @paul: Yes, but that's logical because C++03 didn't even have threads. – MSalters Jun 17 '15 at 15:03
  • So how can I fix this problem if I'm using Visual C++ 2010, does Windows API provide a solution? – paul Jun 17 '15 at 15:04
  • @paul: Use boost - the C++11 solution was directly derived from Boost. Once you upgrade to an up-to-date version of MSVC, you can probably replace `using boost::atomic` with `using std::atomic`. – MSalters Jun 17 '15 at 15:07
  • What if I am only using C and Windows API threads, do you know how to solve this problem? – paul Jun 17 '15 at 15:09
  • @paul: Slap a `CriticalSection` on the variable. You can't expect the most primitive API to offer all the niceties of more advanced API's. – MSalters Jun 17 '15 at 15:12
  • You mean I should wrap the code that accesses (read/write) the variable with a critical section? – paul Jun 17 '15 at 15:15
  • @paul: if you are using Microsoft C and Windows API threads, and dealing with 32-bit integers, `volatile` is probably all you need. Introducing a critical section would be overkill. – Harry Johnston Jun 17 '15 at 23:14
  • ... on the other hand, that depends on how you're using the variable. If you don't understand how multiprocessor CPUs affect thread safety, you may be better off playing it safe and using critical sections after all. – Harry Johnston Jun 17 '15 at 23:32
  • @Harry Johnston So you mean that the value of a 32-bit integer could be cached by each thread, but a `struct` for example will not? – paul Jun 18 '15 at 02:27
  • With a `struct` the problem is that you may see changes for some members before you see changes for others. Similarly, if you print a string while another thread is changing it you might wind up printing some characters from one string and some characters from another. The platforms that Windows runs on all guarantee that when you read a properly aligned 32-bit integer you won't get a mixture of two different values. – Harry Johnston Jun 18 '15 at 02:48
  • @Harry Johnston Should I use `volatile` for each member of a `struct`, or can I just use `volatile` with the entire `struct` when declaring an instance of it (Note that I am talking about `volatile` in MSVC++)? – paul Jun 18 '15 at 03:00
  • You can't use `volatile` to solve that problem. You need a critical section or similar locking mechanism. – Harry Johnston Jun 18 '15 at 03:00
  • @Harry Johnston Isn't a critical section used to force a thread to execute a piece code only when the other thread has finished executing it? What I was talking about is not allowing each thread to make its own "copy" of the variable. – paul Jun 18 '15 at 03:04
  • @paul: A critical section usually protects a shared variable. A single critical section may therefore be locked by multiple functions. – MSalters Jun 18 '15 at 06:56
  • @MSalters Yes, this is what I thought. But a critical section does not prevent each thread from creating its own "copy" of the shared variable, this is the job of `volatile` (at least in MSVC++), correct? – paul Jun 18 '15 at 08:08
  • @paul: Just to make it explicit: what you see is NOT each thread having its own copy. What you see is stale caches, missing register reloads and other Undefined Behavior. To give each thread its own copy, you need [`thread_local`](http://stackoverflow.com/questions/11983875/what-does-the-thread-local-mean-in-c11). – MSalters Jun 18 '15 at 09:21
  • @MSalters Yes, so there is only one copy of the variable in memory, but each CPU can cache the value of the variable in its cache and access the cache from now own (hence the illusion of a separate copy). – paul Jun 18 '15 at 09:30
  • @paul: Indeed, and a CriticalSection will force out stale cache values. – MSalters Jun 18 '15 at 10:54
  • [Under Visual Studio 2005 and later](https://msdn.microsoft.com/en-us/library/windows/desktop/ms686355%28v=vs.85%29.aspx), `volatile` creates a memory barrier "when supported by the CPU". Another option is the [MemoryBarrier](https://msdn.microsoft.com/en-us/library/windows/desktop/ms684208%28v=vs.85%29.aspx) macro. But in most cases if you need to worry about memory caching you also need to worry about thread safety, requiring a critical section or similar. – Harry Johnston Jun 18 '15 at 21:37