2013-11-11 5 views
5

Я ищу оператора компаратора, который может использоваться для сравнения двух атомных переменных атомарно под C++ 11. Здесь я не хочу менять значения, хранящиеся в этих атомных объектах, поэтому мне не интересны функции compare_and_swap. См пример ниже:Atomic Compare Operator (No swap)

std::atomic<uint32_t> readIdx{0}; 
std::atomic<uint32_t> writeIdx{0}; 

while(writeIdx + 1 == readIdx) <<<<------------------ 
{ 
    std::this_thread::yield(); 
} 

Все, что я хочу, чтобы сделать код, изображенный стрелкой линии атомарным. Является ли это возможным? Если нет, то writeIdx == readIdx - это атомная операция?

+2

Что вы подразумеваете под «атомным» здесь? Какая последовательность оценок, которые этот код может заметить, что вы хотите предотвратить? Условие эквивалентно 'writeIdx.load() + 1 == readIdx.load()'. Разумеется, два вызова 'load()' являются атомарными; остальное действует на простые 'uint32_t'. –

+2

@IgorTandetnik: Если в системе есть еще один поток, он может изменить 'writeIdX' после того, как поток OP прочитает его, и прежде чем он прочитает' readIdx'. В этом случае OP, по-видимому, хочет, чтобы два 'load()' вызова выполнялись атомарно * как группа *, а не для каждой отдельной 'load()' для атома (что они, по-видимому, есть). –

+1

@NathanFellman: Как это будет отличаться наблюдаемым поведением от ситуации, когда 'writeIdx' изменяется сразу после загрузки обеих атомов? Конечный результат точно такой же, поэтому почему нужно предотвратить один случай, а не другой? –

ответ

4

Это невозможно, так как это не имеет никакого смысла.

Ваш код получит действительные значения для сравнения, но дает очень мало гарантий, когда эти значения будут получены. Поэтому, если проверка завершается успешно, все, что вы будете знать, это то, что readIdx был в некоторый момент времени равным значению, которое writeIdx + 1 дало в определенный момент времени. Эти два момента времени в основном не связаны. В частности, допускается, чтобы ни в один момент времени значение readIdx не было равно значению writeIdx + 1, но все же проверка прошла успешно.

Вот почему это на самом деле не проблема: вы не сможете установить, что понятие атомистики равно равным в то же время без введения дополнительной блокировки. Проблема в том, что любой код, зависящий от этого условия, должен быть частью того же атомного блока выполнения, который выполняет проверку. Если это не так, условие может измениться, прежде чем код завершит выполнение.

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

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

+1

«Если нет, вы, вероятно, хорошо разбираетесь в своем текущем коде» ... хотя тогда вы не можете не задаться вопросом, почему вы хотели бы выполнить (в основном бессмысленную) проверку в первую очередь. Это не сильно отличается от бросания монеты в этот момент. –

+0

@IgorTandetnik Хорошая точка, общая ценность этой проверки действительно сомнительна. – ComicSansMS

+0

@ComicSansMS: как вы сами указываете, это требование необходимо для того, чтобы избежать того, что вы написали, где «разрешено, чтобы ни в один момент времени значение' readIdx' не было равно значению ' writeIdx + 1', но все же проверка прошла успешно. Дело в том, что, вероятно, это не так тривиально, как ожидал OP. –

Смежные вопросы