18

I recently had an interview with a software company who asked me the following question:

Can you describe to me what adding volatile in front of variables does? Can you explain to me why it's important?

Most of my programming knowledge comes from C, yet the job position is for C# (I thought I might add this bit of info if necessary for the question specifically)

I answered by saying it just lets the compiler know that the variable can be used across processes or threads, and that it should not use optimization on that variable; as optimizing it can deteriorate behavior. In a nutshell, it's a warning to the compiler.

According to the interviewer, however, it's the other way around, and the volatile keyword warns the OS, not the compiler.

I was a bit befuddled by this, so I did some research and actually found conflicting answers! Some sources say it's for the compiler, and others for the OS.

Which is it? Does it differ by language?

dovedevic
  • 673
  • 2
  • 14
  • 33
  • 5
    Yes, it matters by language. My answer to that question would be "No, I can't - not with precision and accuracy." I think that's the *truthful* answer of 99% of C# developers. – Jon Skeet Dec 07 '16 at 20:10
  • Why are they mutually exclusive? The keyword is there to ensure that *nothing* is violating the constraints that `volatile` is there to ensure. This includes the language compiler, the runtime, the operating system, and even the hardware on the CPU. Each layer of abstraction needs to not only not make improper optimizations given the rules `volatile` restricts, and also needs to ensure none of the layers it is built on do so either. – Servy Dec 07 '16 at 20:10
  • @JonSkeet Can you expand on what you mean by the latter half of your comment? – 10101088101010 Dec 07 '16 at 20:11
  • 1
    @10101088101010 Jon is asserting that almost no C# developers, including himself, accurately understand the exact semantics `volatile` results in, even if they might say otherwise. – Servy Dec 07 '16 at 20:13
  • Ah okay! That is indeed interesting... – 10101088101010 Dec 07 '16 at 20:13
  • @Servy post as answer and I'll accept... – 10101088101010 Dec 07 '16 at 20:14
  • 5
    I'm saying that almost no C# developers know what volatile really means in C#. Even MSDN doesn't (the description [here](https://msdn.microsoft.com/en-us/library/x13ttww7.aspx) is an oversimplification). I've read the C# spec several times and the relevant section of the ECMA CLI spec several times, and I believe they're somewhat unclear. Do I have a vague approximation of an understanding? Sure. But could I describe it precisely and accurately? Nope. – Jon Skeet Dec 07 '16 at 20:14
  • @Servy In C# im not sure because it's JIT compiled but how in C after compilation CPU/OS/Runtime would now that "this variable is volatile or not" if it's just following the compiled instructions? volatile in C is solely for compiler. – koper89 Dec 07 '16 at 20:15
  • I think the interviewer is wrong. The compiler has to add code (pseudo ops) to prevent cross-threading. The operating system can't modify the code without the compiler information. It may be the operating system that actually behaves differently, but without the compiler adding marks into the code the Operating System will not know what to do. – jdweng Dec 07 '16 at 20:15
  • 1
    Your C answer is actually very incorrect. – user3528438 Dec 07 '16 at 20:15
  • 4
    No, that is absolutely wrong. It does not warn the OS. You might argue that it informs the *runtime* environment, since C# is a managed language, but `volatile` absolutely does not send any signal to the operating system itself. Jon et al. are right that the semantics of `volatile` in C# are confusing and ill-understood, but there is really no way someone could plausibly argue that it is a semantic hint to the operating system. – Cody Gray - on strike Dec 07 '16 at 20:15
  • 3
    One exception I know about for this is Joe Duffy. He knows. I'm sure some of his old colleagues know as well. Vance Morrison knows. I'm sure some of the equivalent folks on the Mono runtime team know. Basically, it's a handful compared with the swathes of "us common folk" who don't. – Jon Skeet Dec 07 '16 at 20:16
  • 1
    @CodyGray: I'm glad you said that. I was thinking it was runtime rather than OS, too. I would expect it to affect the assembly code generated - and it could involve making system calls - but I would be surprised if the OS *implicitly* got involved. I didn't say so before for fear of being wrong due to my aforementioned ignorance. – Jon Skeet Dec 07 '16 at 20:17
  • @koper89 The compiler would need to ensure that the operations it performed on the underlying runtime provided guarantees such that `volatile` semantics were maintained. How it goes about doing that is its business, and I'm sure the specifics would vary between runtimes, but if a compiler ended up writing out machine code that was instructing the runtime to perform operations that would (potentially) violate the volatile semantics, then that would be a bug in the compiler. – Servy Dec 07 '16 at 20:18
  • 8
    @JonSkeet "us common folk", says the Chuck Norris of programming. – MD XF Dec 07 '16 at 20:18
  • This is outside my scope of experience, but the [Language Specification](https://www.microsoft.com/en-us/download/details.aspx?id=7029) at least mentions this: "These optimizations can be performed by the compiler, by the run-time system, or by hardware. For volatile fields, such reordering optimizations are restricted". Whether "run-time system" (or "hardware", depending on context) counts as "the operating system" I do not know. – Quantic Dec 07 '16 at 20:19
  • if I remember correctly it has to do with compiler. not the OS. It is basically telling the compiler not to optimize it. I absolutely hate when the interviewer keeps saying you are wrong while he/she is wrong. I had a time where the interviewer keeps telling me I need to use gcnew in c# for GC to work. And I was like....Nope! (not gonna mention which but its one of the top 10 software company) – Steve Dec 07 '16 at 20:25
  • @Steve What would be the point in telling the compiler not to re-order certain operations if the OS (or any other layers of abstraction underneath the compiler) is allowed to re-order those operations? If it would be allowed to, then you couldn't assume anything about how the order the operations are performed in, so you might as well not use `volatile` at all. It's only worth using if the constraints it mandes happen are enforced "all the way down". – Servy Dec 07 '16 at 20:30
  • So would it them be a safe assumption to say it's... both? – 10101088101010 Dec 07 '16 at 20:37
  • It would be a safe assumption to say it's... complicated. – Jon Skeet Dec 07 '16 at 20:52
  • 1
    http://joeduffyblog.com/2010/12/04/sayonara-volatile/ – Hackerman Dec 07 '16 at 21:00
  • 1
    [Lippert](http://stackoverflow.com/questions/72275/when-should-the-volatile-keyword-be-used-in-c) – TaW Dec 07 '16 at 21:09
  • 4
    The interviewer is sufficiently wrong that they should not be using volatile in any language. – Eric Lippert Dec 08 '16 at 02:45

2 Answers2

22

I answered by saying it just lets the compiler know that the variable can be used across processes or threads, and that it should not use optimization on that variable; as optimizing it can deteriorate behavior. In a nutshell, it's a warning to the compiler.

This is going in the right direction for C# but misses some important aspects.

First off, delete "processes" entirely. Variables are not shared across processes in C#.

Second, don't concentrate on optimizations. Instead concentrate on permissible semantics. A compiler is not required to generate optimal code; a compiler is required to generate specification-compliant code. A re-ordering need not be for performance reasons and need not be faster / smaller / whatever. A volatile declaration adds an additional restriction on the permissible semantics of a multithreaded program.

Third, don't think of it as a warning to the compiler. It's a directive to the compiler: to generate code that is guaranteed to be compliant with the specification for volatile variables. How the compiler does so is up to it.

The actual answer to the question

Can you describe to me what adding volatile in front of variables does?

is: A C# compiler and runtime environment have great latitude to re-order variable reads and writes for any reason they see fit. They are restricted to only those re-orderings which preserve the meaning of programs on a single thread. So "x = y; a = b;" could move the read of b to before the read to y; that's legal because the outcome is unchanged. (This is not the only restriction on re-ordering, but it is in some sense the most fundamental one.) However, re-orderings are permitted to be noticeable on multiple threads; it is possible that another thread observes that b is read before y. This can cause problems.

The C# compiler and runtime have additional restrictions on how volatile reads and writes may be re-ordered with respect to each other, and furthermore how they may be ordered with respect to other events such as threads starting and stopping, locks, exceptions being thrown, and so on.

Consult the C# specification for a detailed list of the restrictions on observed orderings of reads, writes and other effects.

Note in particular that even with volatile variables, there is not required to be a consistent total ordering of all variable accesses as seen from all threads. And specifically, the notion that volatile "reads the latest value of the variable" is simply false; that phrasing suggests that there is such a thing as "the latest value", which implies a total consistent ordering.

If that sounds confusing, it is. Don't write multithreaded programs that share data across threads. If you must, use the highest level abstractions at your disposal. Hardly anyone should be writing code that uses volatile; use the TPL and let it manage your threads.

Now let's consider your answer in the context of C.

The question is ill-posed with respect to C. In C# volatile is a modifier on member variable declarations; in C, it's part of a type. So saying "before a variable" is ambiguous; where before the variable? There's a difference between a volatile int * x and an int * volatile x. (Can you see the difference?)

But more importantly: the C specification does not guarantee that volatile will have any particular behaviour with respect to threads. If your C compiler does, that's an extension of the language by your compiler vendor. Volatile in C is guaranteed to have certain behaviour with respect to memory mapped IO, long jumps, and signals, and that's all; if you rely on it to have certain behaviour with respect to threads then you are writing non-portable code.

According to the interviewer: it's the other way around, and the volatile keyword warns the OS, not the compiler.

That's nonsense from start to finish. Interviewers should not ask questions that they don't understand the answers to.

Eric Lippert
  • 647,829
  • 179
  • 1,238
  • 2,067
3

To be fairly honest, the question posed by the interviewer is kinda foggy as it is.

It really depends on what he/she meant by "OS". Are they talking about the "upfront OS", the pure software side of things, or what they might be misconstruing the "OS" as the hardware-software relationship, ie the RTE and MMM (I've seen either assumptions and comparisons in some of my own personal interviews). I think it should be noted that these two are quite distinctly different! If he/she is talking about the former, then NO volatile does not "inform" the OS. If they are talking about the latter, then yes (this is a loose yes). At this point you are in the realm of the differences between the languages. As Cody Gray mentioned, C# is a managed language, and so then the latter definition of the OS does indeed "get notified" of the variable and the precautions to take.

But also, in any case or definition of OS, the compiler does specially manage and deal with the volatile field, regardless of language. Otherwise, why have the keyword in the first place?

In my personal opinion, what ever that's worth, I think you answered correctly, albeit, judging by the comments, can get complicated and hectic by nature.

dovedevic
  • 673
  • 2
  • 14
  • 33
  • Interesting... I had no idea that this topic was so grey as opposed to black and white. Thanks for the insight and summary. – 10101088101010 Dec 07 '16 at 20:59
  • 1
    I just want to point out, even though you marked this as the answer, this is by no means a concrete and distinctive answer... as the topic is complicated... – dovedevic Dec 07 '16 at 21:05