Понимание std :: atomic :: compare_exchange_weak () в C ++ 11
bool compare_exchange_weak (T& expected, T val, ..);
compare_exchange_weak()
является одним из примитивов сравнения-обмена, представленных в C ++ 11. Этослабый в том смысле, что он возвращает false, даже если значение объекта равноexpected
, Это связано сложный сбой на некоторых платформах, где для его реализации используется последовательность инструкций (вместо одной, как на x86). На таких платформах переключение контекста, перезагрузка одного и того же адреса (или строки кэша) другим потоком и т. Д. Может дать сбой примитиву. Этоspurious
поскольку это не стоимость объекта (не равноexpected
), который терпит неудачу операции. Вместо этого это проблемы с выбором времени.
Но что меня озадачивает, так это то, что сказано в стандарте C ++ 11 (ISO / IEC 14882),
29.6.5. Следствием случайного сбоя является то, что почти все виды использования слабого сравнения и обмена будут в цикле.
Почему это должно быть в циклепочти все использует ? Означает ли это, что мы будем зацикливаться, когда он выходит из строя из-за ложных сбоев? Если это так, то зачем нам использоватьcompare_exchange_weak()
и сами напишем цикл? Мы можем просто использоватьcompare_exchange_strong()
который, я думаю, должен избавить нас от ложных неудач для нас. Каковы общие случаи использованияcompare_exchange_weak()
?
Еще один вопрос, связанный. В своей книге «Параллельность в C ++ в действии» Энтони говорит:
//Because compare_exchange_weak() can fail spuriously, it must typically
//be used in a loop:
bool expected=false;
extern atomic<bool> b; // set somewhere else
while(!b.compare_exchange_weak(expected,true) && !expected);
//In this case, you keep looping as long as expected is still false,
//indicating that the compare_exchange_weak() call failed spuriously.
Почему!expected
там в состоянии цикла? Есть ли это, чтобы предотвратить голодание всех потоков в течение некоторого времени?
Изменить: (последний вопрос)
На платформах, где нет единой аппаратной инструкции CAS, слабая и сильная версии реализуются с использованием LL / SC (например, ARM, PowerPC и т. Д.). Так есть ли разница между следующими двумя циклами? Почему, если есть? (Для меня они должны иметь аналогичную производительность.)
// use LL/SC (or CAS on x86) and ignore/loop on spurious failures
while (!compare_exchange_weak(..))
{ .. }
// use LL/SC (or CAS on x86) and ignore/loop on spurious failures
while (!compare_exchange_strong(..))
{ .. }
Я подхожу к этому последнему вопросу, который вы, ребята, все упоминаете, что, возможно, разница в производительности внутри цикла. Это также упоминается в стандарте C ++ 11 (ISO / IEC 14882):
Когда сравнение и обмен находятся в цикле, слабая версия приведет к лучшей производительности на некоторых платформах.
Но, как было проанализировано выше, две версии в цикле должны давать одинаковую / аналогичную производительность. Что я скучаю?