Минимальные требования к заказу

Позволять x а также y быть двумя разными переменными типа std::atomic<int> и предположим, что текущая стоимость обоих из них 1. Каков наиболее свободный набор требований к порядку, чтобы следующий код генерировал некоторые выходные данные? (т.е. что следует использовать дляorder1... order4?)

// Thread 1
x.store(0, order1);       // A
if(0 == y.load(order2))   // B
  std::cout << '1';       // C
// Thread 2
y.store(0, order3);       // E
if(0 == x.load(order4))   // F
  std::cout << '2';       // G

3 ответа

Решение

Вам нужна последовательная согласованность всех операций.

Освобождение / получение фактически не налагает никакого упорядочивания здесь, поскольку нет хранилища перед выпуском-хранением или загрузки после получения-загрузки, которые были бы упорядочены им.

Расслабляющая память, заказывающая в любом из магазинов, например x.storeможет привести к тому, что магазины станут видны в разном порядке в двух потоках. Тогда это не нарушает последовательного упорядочения остальных операций, чтобы ослабленное хранилище было видимым после загрузки в другом потоке, в то время как другое хранилище по-прежнему упорядочивается после соответствующей загрузки в последовательно согласованном общем порядке.

При последовательном упорядочивании всех операций вывод гарантирован, потому что общий порядок последовательных операций должен соблюдаться одинаково во всех потоках. Этот порядок должен соответствовать порядку следования в потоках, т. Е.x.store < y.load а также y.store < x.load. Единственные возможности:

x.store < y.load  < y.store < x.load
x.store < y.store < x.load  < y.load
x.store < y.store < y.load  < x.load

y.store < x.load  < x.store < y.load
y.store < x.store < y.load  < x.load
y.store < x.store < x.load  < y.load

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

Если например x.store не является memory_order_seq_cst, затем, пока его еще нужно упорядочить перед y.load в потоке 1 это могло стать видимым после x.load в потоке 2.

y.load < y.store < x.load тогда по-прежнему будет удовлетворять последовательная согласованность других операций и порядок модификации x в любом случае тривиально удовлетворяется.

#StoreLoad переупорядочение может привести к тому, что обе загрузки вернут старое значение, поэтому для предотвращения этого вам потребуется полная последовательная согласованность всех 4 операций.

Прочтите информацию о буферах хранилища, чтобы понять, что вызывает этот тип переупорядочения.

Два простых правила:

  • как первое действие после начала параллелизма (запуск потоков), ограждение выпуска или операция не имеет ничего, что можно было бы сделать видимым (в других потоках), поэтому ничего не "выпускается" и выпуск бесполезен (все ранее было видно и одинаково виден одновременно запущенным потокам);
  • как последнее действие перед завершением параллелизма (конец потоков), ограждение или операция получения не имеет ничего, что можно было бы сделать видимым (в этом потоке), что не было бы видимым в общем родительском потоке

Здесь у вас есть:

x.store(0, order1);       // A
if(0 == y.load(order2))   // B
  • магазин в начале
  • груз в конце

так что ни приобретение, ни выпуск семантики не могут иметь никакого значения.

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