Минимальные требования к заказу
Позволять 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
- магазин в начале
- груз в конце
так что ни приобретение, ни выпуск семантики не могут иметь никакого значения.