AdvSphere
AdvSphere

Reputation: 986

Memory barrier scope

I'm not sure what's the scope of std::memory_order_release or std::memory_order_acquire memory barriers. Below is an example taken from cppreference. I tweaked the code to make my point:

#include <atomic>
#include <cassert>
#include <string>
#include <thread>
#include <iostream>

std::atomic<std::string*> ptr;

void producer()
{
  std::string* p  = new std::string("Hello");

  ptr.store(p, std::memory_order_release);
}

bool acquire(std::string* p2)
{
  while (!(p2 = ptr.load(std::memory_order_acquire)));

  return p2 != nullptr;
}

void consumer()
{
  std::string* p2 {nullptr};

  // while (!(p2 = ptr.load(std::memory_order_acquire))); // prints "makes sense"
  assert(acquire(p2)); // prints "what's going on?"

  if (p2 == nullptr)
  {
    std::cout << "what's going on?" << std::endl;
  }
  else
  { 
    std::cout << "makes sense" << std::endl;
  }
}

int main()
{
  std::thread t1(producer);
  std::thread t2(consumer);
  t1.join(); t2.join();
}

The output of the above code is what's going on?

I'm familiar (not expert) with memory barriers. From the test above I have the following questions:

  1. The std::memory_order_acquire used in acquire() function only is used for the scope of acquire(), based on the output of the program since uncommenting while(...) prints the expected output "makes sense". Does this make sense? am I missing anything?

  2. How is it possible to print "what's going on?", the assert(acquire(p2)) makes it clear p2 is not nullptr, but somehow it reads the nullptr value in the if conditional. I'm not an expert in out of order execution rules, but I'd expect that p2 = nullptr is honored before calling acquire(), since acquire() depends on it.

Upvotes: 1

Views: 421

Answers (1)

Drew Dormann
Drew Dormann

Reputation: 63735

  1. The std::memory_order_acquire used in acquire() function only is used for the scope of acquire()

No. It applies to the thread and is not bound by any function boundaries.

  1. How is it possible to print "what's going on?"

Because you are modifying a copy of the pointer. Change:

bool acquire(std::string* p2)

to:

bool acquire(std::string*& p2)

to make the function reference the same pointer that's being passed to it.

Upvotes: 4

Related Questions