Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Risks of volatile-mutable fields in single-threaded contexts?

Is it safe to use the :volatile-mutable qualifier with deftype in a single-threaded program? This is a follow up to this question, this one, and this one. (It's a Clojure question, but I added the "Java" tag because Java programmers are likely to have insights about it, too.)

I've found that I can get a significant performance boost in a program I'm working on by using :volatile-mutable fields in a deftype rather than atoms, but I'm worried because the docstring for deftype says:

Note well that mutable fields are extremely difficult to use correctly, and are present only to facilitate the building of higher level constructs, such as Clojure's reference types, in Clojure itself. They are for experts only - if the semantics and implications of :volatile-mutable or :unsynchronized-mutable are not immediately apparent to you, you should not be using them.

In fact, the semantics and implications of :volatile-mutable are not immediately apparent to me.

However, chapter 6 of Clojure Programming, by Emerick, Carper, and Grand says:

"Volatile" here has the same meaning as the volatile field modifier in Java: reads and writes are atomic and must be executed in program order; i.e., they cannot be reordered by the JIT compiler or by the CPU. Volatiles are thus unsurprising and thread-safe — but uncoordinated and still entirely open to race conditions.

This seems to imply that as long as accesses to a single volatile-mutable deftype field all take place within a single thread, there is nothing to special to worry about. (Nothing special, in that I still have to be careful about how I handle state if I might be using lazy sequences.) So if nothing introduces parallelism into my Clojure program, there should be no special danger to using deftype with :volatile-mutable.

Is that correct? What dangers am I not understanding?

like image 977
Mars Avatar asked May 27 '15 03:05

Mars


1 Answers

That's correct, it's safe. You just have to be sure that your context is really single-threaded. Sometimes it's not that easy to guarantee that.

There's no risk in terms of thread-safety or atomicity when using a volatile mutable (or just mutable) field in a single-threaded context, because there's only one thread so there's no chance of two threads writing a new value to the field at the same time, or one thread writing a new value based on outdated values.

As others have pointed out in the comments you might want to simply use an :unsynchronized-mutable field to avoid the cost introduced by volatile. That cost comes from the fact that every write must be committed to main memory instead of thread local memory. See this answer for more info about this.

At the same time, you gain nothing by using volatile in a single-threaded context because there's no chance of having one thread writing a new value that will not be "seen" by other thread reading the same field. That's what a volatile is intended for, but it's irrelevant in a single-thread context.

Also note that clojure 1.7 introduced volatile! intended to provide a "volatile box for managing state" as a faster alternative to atom, with a similar interface but without it's compare and swap semantics. The only difference when using it is that you call vswap! and vreset! instead of swap! and reset!. I would use that instead of deftype with ^:volatile-mutable if I need a volatile.

like image 134
nberger Avatar answered Oct 21 '22 00:10

nberger