0

I'm checking this great post on java fences, in which fences are used for following example, to ensure that concurrent thread can always read latest value updated from other threads:

// CPU 0:
void shutDownWithFailure(void)
{
  failure = 1; // must use SOB as this is owned by CPU 1
  SFENCE // next instruction will execute after all SOBs are processed
  shutdown = 1; // can execute immediately as it is owned be CPU 0
}
// CPU1:
void workLoop(void)
{
  while (shutdown == 0) { ... }
  LFENCE // next instruction will execute after all LOBs are processed
  if (failure) { ...}
}

My question is, what's the advantage of using fences against volatile.
Taking above example, if I make both failure and shutdown volatile, it should achieve the same?

wayne
  • 598
  • 3
  • 15
  • 1
    Pretty sure only `shutdown` needs to be `volatile` for this to work without separate fences. You'd get release / acquire synchronization, guaranteeing that a reader seeing `shutdown == 1` would also see `failure == 1`. – Peter Cordes Mar 27 '22 at 19:41

1 Answers1

1

I would say, it's all described in the JEP 171 that is linked to that question, in the "Motivation" section at the top. To sum it up: it is meant to provide a documented way to access these mechanisms and to provide further implementations and extensions of the classes for concurrent access.

Doesn't mean to use them is always an advantage over volatile.

cyberbrain
  • 3,433
  • 1
  • 12
  • 22
  • Thanks @cyberbrain. Would you know in which case will fence be the better choice than volatile? – wayne Mar 27 '22 at 13:24
  • No, sorry, I don't know. In case it wasn't obvious: I'm no expert in that field, so I just gave an answer as vague as a politician to a TV reporter ;) Maybe this answer helps you better (tl;dr: it's all about performance): https://stackoverflow.com/a/60130907/2846138 – cyberbrain Mar 27 '22 at 13:53
  • 1
    @wayne: Separate fences can be useful as part of a SeqLock, where you need to stop the 2nd atomic load of the sequence number from reordering with *earlier* non-atomic loads, opposite of what acquire semantics gives you. e.g. in C++ [Implementing 64 bit atomic counter with 32 bit atomics](https://stackoverflow.com/q/54611003). (But note that despite your use of the LFENCE name, you don't actually want an x86 `lfence` instruction; it's not useful for memory ordering of normal loads. A JVM would only need to make sure x86 load instructions are in the right order on strongly-ordered x86.) – Peter Cordes Mar 27 '22 at 19:44
  • 1
    [Using JDK 9 Memory Order Modes](http://gee.cs.oswego.edu/dl/html/j9mm.html) is a good read. I've used weaker ordering when piggybacking on another fence, e.g. writes only occur under a lock and flush on its release. Trying to optimize at this level is error prone (e.g. [JDK-8078490](https://bugs.openjdk.java.net/browse/JDK-8078490), [cats-effect's naivety](https://www.youtube.com/watch?v=EFkpmFt61Jo)). I try to ensure my usages are benign or else use stronger modes as the performance change is miniscule. – Ben Manes Mar 28 '22 at 00:06