Объем барьера памяти

Я не уверен, каковы возможности барьеров памяти std::memory_order_release или std::memory_order_acquire. Ниже приведен пример из cppreference. Я изменил код, чтобы выразить свою точку зрения:

#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();
}

Результатом приведенного выше кода является what's going on?.

Я знаком (не эксперт) с барьерами памяти. Из теста выше у меня есть следующие вопросы:

  1. std::memory_order_acquire, используемый в функции acquire(), используется только в рамках acquire(), на основе вывода программы, поскольку при раскомментировании while(...) ожидаемый вывод «имеет смысл». Имеет ли это смысл? я что-нибудь упускаю?

  2. Как можно напечатать «что происходит?», assert(acquire(p2)) дает понять, что p2 не является nullptr, но каким-то образом считывает значение nullptr в условном if. Я не эксперт в правилах исполнения вне очереди, но я ожидаю, что p2 = nullptr соблюдается перед вызовом acquire(), since acquire() зависит от этого.

Не имеет ничего общего с семантикой памяти. В одном случае вы напрямую назначаете указатель, который вы печатаете, в другом - нет.

Barry 13.09.2018 21:43

У вас два разных std::string* p2. Это не одна и та же переменная! Вы назначаете один, а затем проверяете, является ли другой по-прежнему нулевым.

Drew Dormann 13.09.2018 21:46

@ Дрю Дорманн, спасибо! глупая ошибка с моей стороны. Я еще раз редактирую вопрос.

AdvSphere 13.09.2018 21:51

@AdvSphere Я отправил ответ. Пожалуйста, отправьте вопрос новый, если у вас есть новый, другой вопрос.

Drew Dormann 13.09.2018 21:51

@Drew Dormann подойдет! еще раз спасибо!

AdvSphere 13.09.2018 21:53

у барьеров памяти нет «размаха». ptr.store(p, std::memory_order_release); является точкой синхронизации с ptr.load(std::memory_order_acquire). все записи в producer до этой точки видны в consumer после просмотра результата ptr, записанного производителем

RbMm 13.09.2018 22:04

утверждать (приобретать (p2)); // будет пропущено в релизе.

M.L. 14.09.2018 16:27
1
7
171
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий
  1. The std::memory_order_acquire used in acquire() function only is used for the scope of acquire()

Нет. Он применяется к нить и не связан какими-либо границами функций.

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

Потому что вы изменяете копировать указателя. Изменять:

bool acquire(std::string* p2)

к:

bool acquire(std::string*& p2)

чтобы сделать функцию ссылка тем же указателем, который ей передается.

Другие вопросы по теме