Подтвердить что ты не робот

Std:: atomic <int> декремент и сравнение

В следующем коде:

std::atomic<int> myint; //Shared variable
//(...)
if( --myint == 0) {
    //Code block B
}

Возможно ли, что более одного потока обращается к блоку, который я назвал "Code Block B"?

Пожалуйста, учтите, что переполнение не произойдет, что "if" выполняется одновременно несколькими потоками, что единственная модификация myint во всей программе - это -myint внутри if, и этот myint инициализируется с помощью положительное значение.

4b9b3361

Ответ 1

С++ 0x paper N2427 (atomics) утверждает примерно следующее. Я немного изменил формулировку, поэтому ее легче читать для конкретной ситуации декремента, части, которые я изменил, находятся в жирным:

Эффекты: Атомно заменить значение в объекте результатом декремента, применяемого к значению в объекте и заданном операнде. Память зависит от порядка. Эти операции - операции чтения-изменения-записи в смысле определения "синхронизируются с" в [новом разделе, добавленном N2334 или преемником], и, следовательно, обе такие операции и оценка, которые дали входное значение, синхронизируются с любой оценкой, которая читает обновленное значение.

Возвращает:    Атомно значение объекта непосредственно перед декретом.

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

Это означает, что единственные возможные исполнения этого кода с двумя потоками:

(Initial Value: 1)
Thread 1: Decrement 
Thread 1: Compare, value is 0, enter region of interest
Thread 2: Decrement
Thread 2: Compare, value is -1, don't enter region

или

(Initial Value: 1)
Thread 1: Decrement 
Thread 2: Decrement
Thread 1: Compare, value is 0, enter region of interest
Thread 2: Compare, value is -1, don't enter region

Случай 1 - это неинтересный ожидаемый случай.

Случай 2 перемежает операции декремента и выполняет последующие операции сравнения. Поскольку операция декремента и выборки является атомарной, для потока 1 невозможно получить значение, отличное от 0 для сравнения. Он не может получить -1, потому что операция была атомарной... чтение происходит во время декремента, а не во время сравнения. Больше потоков не изменит этого поведения.

Ответ 2

Не очевидно, что блок кода всегда будет выполняться. Если оператор "-" реализован таким образом, что он сохраняет старое значение в возвращаемом значении и декрементах в одной атомной инструкции (я уверен, что x86 имеет такие инструкции), тогда да, он должен действовать как блок взаимного исключения для нескольких потоков. Я не уверен, как это работает по умолчанию, но ответ лежит, вероятно, в новой стандартной документации:

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2427.html

Ответ 3

Нет, невозможно, чтобы в блок попало более одного потока, учитывая ваши ограничения. Но ни один из них не гарантирует, что какой-либо поток когда-либо входит в этот блок:

thread A: decrement myint to 0

thread B: decrement myint to -1

thread A: compare to 0 -> false -> don't enter (and neither anyone else)

Если это проблема (я предполагаю), то этот код не будет работать (по крайней мере, не всегда).