0

Most blogsites like this one for example when explaining about memory_order_seq_cst always talks about this example

std::atomic<bool> x{false}, y{false};
std::atomic<int> z{0};

void thread1() {
 x.store(true, std::memory_order_seq_cst); // (1)
}

void thread2() {
 y.store(true, std::memory_order_seq_cst); // (2)
}


void read_x_then_y() {
    while (!x.load(std::memory_order_seq_cst)); // (3)
    if (y.load(std::memory_order_seq_cst)) ++z; // (4)
}

void read_y_then_x() {
    while (!y.load(std::memory_order_seq_cst)); // (5)
    if (x.load(std::memory_order_seq_cst)) ++z; // (6)
}

int main() 
{
 std::thread a(thread1), b(thread2), c(read_x_then_y), d(read_y_then_x);
 a.join(), b.join(), c.join(), d.join();
 assert(z.load() != 0); // (7)
}

When translating this into java code i get this

 public static void main(String[] args)throws Exception
 {
  AtomicBoolean 
  x=new AtomicBoolean(false),
  y=new AtomicBoolean(false);
  AtomicInteger z=new AtomicInteger(0);
  
  while(true)
  {
   z.set(0);
   
   Thread t1=new Thread(()->x.set(true));
   
   Thread t2=new Thread(()->y.set(true));
   
   Thread t3=new Thread(()->
   {
    while(!x.get()){}
    if(y.get()){z.incrementAndGet();}
   });
   
   Thread t4=new Thread(()->
   {
    while(!y.get()){}
    if(x.get()){z.incrementAndGet();}
   });
   
   t1.start();
   t2.start();
   t3.start();
   t4.start();
   
   t1.join();
   t2.join();
   t3.join();
   t4.join();
   
   assert(z.get()!=0);
  }
 }

The whileloop is used to generate infinite test cases to see if the assert fails at any point and the set() from the documentation has similar memory effects to setVolatile() which if we read from the API note has memory effects like memory_order_seq_cst

This example works but i fell is deceptive because it does not explain how memory_order_seq_cst ensures the assertion is always true. The program itself appears to be written in such a way that regardless of what memory_order method you use to load/store

set(),setPlain(),setOpaque(),setRelease()
get(),getPlain(),getOpaque(),getAquire()

the assertion always succeeds and it never fails so how exactly does memory_order_seq play a unique role in this example?

Sync it
  • 1,180
  • 2
  • 11
  • 29
  • 1
    This is the IRIW litmus test. Unless you tested on a recent PowerPC server, all threads will agree on the order of stores, even if the stores are `relaxed` and the loads are just `acquire`. ISO C++ doesn't guarantee it without `seq_cst`, but it also doesn't guarantee that every allowed ordering actually will be observed in practice. Especially ones the hardware you choose doesn't do naturally. (The loads do need to be `acquire` so it doesn't fail because of local load-load reordering on the readers, actually observing the global order of store visibility) – Peter Cordes Oct 06 '22 at 16:34
  • Does this answer your question? [Will two atomic writes to different locations in different threads always be seen in the same order by other threads?](https://stackoverflow.com/questions/27807118/will-two-atomic-writes-to-different-locations-in-different-threads-always-be-see) Also [Acquire/release semantics with 4 threads](https://stackoverflow.com/q/48383867) And comments on [Still can't get a true root cause explanation on IRIW scenario](https://stackoverflow.com/q/69003544) – Peter Cordes Oct 06 '22 at 16:34
  • 1
    If you were testing this on x86 hardware, [What does it mean that "two store are seen in a consistent order by other processors"?](https://stackoverflow.com/q/63912669) is a duplicate that explains why you can't observe IRIW reordering on that system. – Peter Cordes Oct 06 '22 at 16:37

0 Answers0