Почему все функции-члены в std::atomic появляются как с volatile, так и без него?

Я заметил, что большинство функций-членов std::atomic<T> типы объявляются дважды, один раз с volatile модификатор и один раз без ( пример)). Я проверил исходный код реализации стандартной библиотеки G++ и обнаружил, что все они являются точными дубликатами, например:

bool
load(memory_order __m = memory_order_seq_cst) const noexcept
{ return _M_base.load(__m); }

bool
load(memory_order __m = memory_order_seq_cst) const volatile noexcept
{ return _M_base.load(__m); }

Я не смог найти ни одного примера, где volatile вариант ведет себя иначе, чем не volatile один, отличается по типу возврата или что-нибудь в этом роде.

Это почему? Я думал volatile функция-член также может быть вызвана в объектах, которые не являются volatile, Так декларируя и определяя std::atomic::load(...) const volatile noexcept и т.д. должно быть достаточно.

Обновить:

Основываясь на комментариях, мой вопрос сводится к следующему: Можете ли вы привести пример, когда некоторые звонки с использованием volatile экземпляр (не обязательно std::atomic) будет генерировать другую сборку в двух следующих случаях,

  1. каждая функция-член появляется с одним и тем же телом с и без volatile,

  2. только volatile вариант существует?

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

1 ответ

Решение

Вероятно, все это связано с тем, что volatile есть, для этого см. этот ответ. Поскольку варианты использования довольно тонкие по сравнению с обычной разработкой приложений, поэтому обычно это никого не волнует. Я предполагаю, что у вас нет практического сценария, в котором вы задаетесь вопросом, следует ли применять эти изменчивые перегрузки. Затем я попытаюсь привести пример, в котором они могут вам понадобиться (не думайте, что он слишком реален).

volatile std::sig_atomic_t status = ~SIGINT;
std::atomic<int> shareable(100);

void signal_handler(int signal)
{
  status = signal;
}

// thread 1
  auto old = std::signal(SIGINT, signal_handler);
  std::raise(SIGINT);
  int s = status;
  shareable.store(10, std::memory_order_relaxed);
  std::signal(SIGINT, old);

// thread 2
  int i = shareable.load(std::memory_order_relaxed);

memory_order_relaxed гарантирует атомарность и последовательность изменений порядка, без побочных эффектов. volatile нельзя переупорядочить с побочными эффектами. Тогда вот мы, в теме 2 вы можете получить shareable равно 10, но статус все еще не SIGINT, Однако, если вы установите квалификатор типа в volatile из shareable это должно быть гарантировано. Для этого вам понадобятся методы volatile-qualified.

Зачем тебе вообще делать что-то подобное? Я мог бы подумать, что у вас есть старый код, использующий старый volatileна основе материала, и вы не можете изменить его по той или иной причине. Трудно представить, но я предполагаю, что может возникнуть необходимость иметь какой-то гарантированный порядок между atomic а также volatile встроенная сборка. Суть в том, ИМХО, что когда это возможно, вы можете использовать новую атомарную библиотеку вместо volatile объекты, в случае, если есть некоторые volatile объекты, от которых вы не можете избавиться и которые хотите использовать atomic объекты, то вам может понадобиться volatile квалификатор для atomic объекты должны иметь надлежащие гарантии упорядочения, для этого вам потребуется перегрузка.

ОБНОВИТЬ

Но если все, что я хотел, - это использовать атомарные типы как энергозависимые, так и энергонезависимые, почему бы просто не реализовать первые?

struct Foo {
    int k;
};

template <typename T>
struct Atomic {
  void store(T desired) volatile { t = desired; }
  T t;
};

int main(int i, char** argv) {
    //error: no viable overloaded '='
    // void store(T desired) volatile { t = desired; }
  Atomic<Foo>().store(Foo());
  return 0;
}

То же самое было бы с load и другие операции, потому что обычно это не тривиальные реализации, которые требуют оператора копирования и / или конструктора копирования (который также может volatile или неvolatile).

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