Risks of mutable variable fields in single-threaded contexts?

Is it possible to use the :volatile-mutable deftype with deftype in a single-threaded program? This is the next question , this and this . (This is a Clojure question, but I added the "Java" tag because Java programmers can also get information about this.)

I found that I can increase significant performance in the program I'm working on using fields :volatile-mutable in deftype , not in atoms, but I'm worried because the docstring for deftype says:

Note that mutable fields are extremely difficult to use correctly, and are only present to facilitate the creation of higher Clojure type constructors in Clojure itself. They are intended only for experts - if the semantics and consequences of: volatile-mutable or: unsynchronized-mutable are not immediate, you should not use them.

In fact, the semantics and consequences :volatile-mutable not immediately obvious to me.

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

"Flying" here has the same meaning as a mutable field modifier in Java: reading and writing are atomic and must be executed in the order of the program; that is, they cannot be reordered by the JIT compiler or processor. Thus, volatiles are unsurprising and thread safe, but inconsistent and still completely open to race conditions.

This seems to imply that as long as access to one mutable deftype mutable field all happens within the same thread, there is nothing to worry about. (Nothing special, since I still need to be careful about how I handle state if I can use lazy sequences.) Therefore, if nothing introduces parallelism into my Clojure program, there should be no particular danger to using deftype with :volatile-mutable .

It is right? What dangers do I not understand?

+6
source share
1 answer

Right, safe . You just have to be sure that your context is truly single threaded. Sometimes it’s not so easy to guarantee.

When using a mutable (or simply mutable) field in a single-threaded context, there is no risk from the point of view of thread safety or atomicity , because there is only one thread, so there is no possibility for two threads writing a new value to the field at the same time or one thread writing a new value based on obsolete values.

As other comments pointed out, you can simply use the :unsynchronized-mutable field to avoid the costs caused by volatility. This cost comes from the fact that each record must be tied to the main memory instead of the local network of the stream. See this answer for more information on this.

At the same time, you do not get anything using volatile in a single-threaded context, because it is not possible to have one thread writing a new value that will not be "visible" by another thread reading the same field. What volatile is for, but it doesn't matter in a single-thread context.

Also note that clojure 1.7 introduced volatile! designed to provide a “volatile state management box” as a faster alternative to atom , with a similar interface, but without it the semantics are compared and replaced. The only difference when using it is that you call vswap! and vreset! instead of swap! and reset! . I would use this instead of deftype with ^:volatile-mutable if I need mutability.

+3
source

Source: https://habr.com/ru/post/987969/


All Articles