0

For the primitive, I think it's necessary. Even for the non-primitive, for example an array, I think it's also necessary.

Without volatile:

int d[2];

Thread 1:

while (d[1] > 0) modify(d[0]);

Thread 2:

while (d[0] > 0) modify(d[1]);

I am afraid that the compiler change my code as follow, when without volatile. while (true) modify();

So I put volatile before 'int d[2]'; But I feel a little strange with everything decorated with volatile.

billz
  • 44,644
  • 9
  • 83
  • 100
hello.co
  • 746
  • 3
  • 21
  • 4
    volatile has nothing to do with multithreading. atomic does. I'd suggest reading [C++ Concurrency In Action](http://www.amazon.com/C-Concurrency-Action-Practical-Multithreading/dp/1933988770/ref=sr_1_1?ie=UTF8&qid=1367134728&sr=8-1&keywords=C%2B%2B+concurrency). – derpface Apr 28 '13 at 07:34
  • 1
    The best answer is to look at documentation for both `volitile` and `atomic` in a C++ book. T'would be difficult and duplicative to cover every subtlety here. – jpaugh Apr 28 '13 at 07:36
  • Here's a resource: http://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list – jpaugh Apr 28 '13 at 07:38

3 Answers3

5

No, that's not what volatile is used for. Volatile is used for variables which may changed outside your program - for eg. memory mapped devices, graphics memory etc.

It's not necessary just because a program is multithreaded - neither for primitive types nor for arrays.

user93353
  • 13,733
  • 8
  • 60
  • 122
3

No. Volatile is for variables that may be read and/or written without the compiler knowing about it. Although another thread changing the variable might look like that situation, volatile is not enough nor actually needed for multithreading programming.

Unless you are writing the synchronization primitives yourself, but that is way more difficult to do right than it seems. And it seems hard enough...

For more details you can read the Linux insight about this issue at Volatile considered harmful. The article is for C, not C++, but the same principles apply.

Alex Chamberlain
  • 4,147
  • 2
  • 22
  • 49
rodrigo
  • 94,151
  • 12
  • 143
  • 190
-2

In this case, there are two threads are "modifying each other's data", which indeed would require the compiler to KNOW that the data is being modified by another thread. There are several solutions to solve this, volatile will tell the compiler that it can't store the value in a register from the first read, but there are problems with that....

Most importanly, volatile will NOT solve the problem of precisely detecting the "edge" when the d[1] > 0 is being changed, since with volatile, all you are guaranteed is that the compiler doesn't remove the read of the variable. In a system with multiple cores, there could well be a "delay" between the new data in thread 1 reaching thread 2. Meaning that d[0] may be modified more times than you expected, because the loop ran a few extra cycles. In extreme cases, such as certain models of ARM processors, the loop may run more or less indefinitely since the processor(core) will need the cache-line flushed, and that will not happen without intervention unless something else is using that same cache-line. In a system that is otherwise not busy, this may take as long as you've got, or longer... ;)

So, I don't agree that volatile isn't needed in multithreaded environments, but I do agree that it's not the whole solution. The std::atomic and other similar constructs are required to ensure the correctness if detecting values has changed "immediately" is needed for the code to work correctly.

Sharing data across threads is a difficult matter, and it needs careful planning and understanding to make it work right. I know the above code is probably just a simplified example, but if modify(d[1]) is trivial, then it would be a very bad case of sharing data, and it is likely that it will run MUCH slower as two threads than as single-threaded loop, because every cache-line write by one processor will force a flush of the cache-line on the other processor. So it will be like driving a Ferrari sports car in busy Manhattan traffic - not very energy efficient, and no faster than the simple solution.

Mats Petersson
  • 126,704
  • 14
  • 140
  • 227
  • 2
    Can site an instance where `volatile` _needed_ in a multi-threaded program, i.e. where the underlying issue cannot be solved as correctly with alternative primitives such as semaphores, atomic objects or mutexes? – CB Bailey Apr 28 '13 at 08:47
  • 2
    Even more, can you find an example where `volatile` can be used safely (and portably) to do inter-thread communication _without_ additional primitives or assembly? – rodrigo Apr 28 '13 at 09:32
  • Absolutely: If you have a variable that is updated in a thread, and you just want a snapshot, but not necessarily an accurate value, for progress reporting. No need for semaphores, atomics or mutexes to fetch "how many bytes have we written of the 4GB that we're copying?" [It is not 100% portable, as I described above, as it assumes that the caches are kept consistent by hardware, which isn't always the case, but there are certainly plenty of software written that has more portability issues than that]. – Mats Petersson Apr 28 '13 at 15:11
  • However, like I said in the last paragraph, you can't rely on this for proper communication, where both sides are guaranteed to see the same updates "simultaneously", volatile is definitely not enough. All I'm trying to say is that `volatile` has a place. You need to know what it means, and use it correctly. I think I made that quite clear. – Mats Petersson Apr 28 '13 at 15:16
  • Made the "however" statement bold to make it clearer for those that downvoted this that I do not SAY "This shold be solved with volatile". Unless the downvotes are for some other reason, in which case I'd like to know what I'm doing wrong. – Mats Petersson Apr 28 '13 at 15:42
  • 1
    Well just starting with the first paragraph: _"requiring volatile to guarantee that the compiler doesn't read the value once and then loop around forever with the original value held in a temporary register"_ -- that's wrong, `volatile` is not "required" for that, there are other (better) ways to get that guarantee without involving `volatile`. Volatile has no place in MT programs, your answer is wrong and highly misleading. – Jonathan Wakely Apr 28 '13 at 15:46
  • Also, read the C++11 definition of a data race and consider what difference `volatile` makes. – Jonathan Wakely Apr 28 '13 at 15:53
  • I've reworded the first paragraph of the answer. It really depends on what you are trying to achieve, however. Is it enough to stop the thread some time after the value of `d[x] < 0`, or does it have to stop IMMEDIATELY as it reaches a value that satisfies that criteria. It is not clear what the requirement is here. But I also think it's wrong to say that `volatile` can't be used in threaded programming. You just have to realize the limitations, and understand what `volatile` actually means - and of course, what the portability requirements are for the code. – Mats Petersson Apr 28 '13 at 15:56
  • 3
    If you realise what `volatile` actually means then you don't use it for MT programs :-P `volatile` is neither necessary not sufficient for correctness when sharing data between threads. Just Say No. – Jonathan Wakely Apr 28 '13 at 15:58