c : значение атомной переменной недопустимо при сохранении в локальной переменной

#c #objective-c #c 11 #stl #synchronization

#c #objective-c #c 11 #stl #синхронизация

Вопрос:

Я определил атомарную переменную current внутри некоторого файла Obj-C.:

 std::atomic<long long> current;
  

после этого оно было инициировано:

 current=4;
  

После этого переменная стала доступной по количеству потоков.
Некоторые потоки модифицировали переменную следующим образом:

 current=(current.fetch_add(1))%4;
  

В то время как другие потоки изменяли переменную по-другому:

 current.fetch_add(1);
if(current>=4){
    current=0;
}
  

Наконец, выполняется следующая строка:

 long long cs=current;
  

На этом этапе произошло нечто странное: в отладчике появляется, что cs равно 4, в то время как current имеет другое значение, обычно 1.
Я ожидал, что cs должен иметь последнее значение current и никогда не должен превышать 3 .
Я проверил все другие экземпляры current ; их не так много, и они используются везде должным образом.
Чего мне не хватает?

Комментарии:

1. Неправильные ожидания атомарного поведения. Скачки между чтением и записью.

2. только опечатка, ничего больше.

3. Может быть много путей выполнения, которые приведут к наблюдаемым результатам. Показанные шаблоны доступа фундаментально нарушены для их заявленной цели.

4. Примечание: current=4; это присваивание, а не инициализация.

Ответ №1:

Атомарные значения не являются примитивами синхронизации. Один из возможных потоков выполнения:

 current.fetch_add(1);  // T1
long long cs=current;  // T2
if(current>=4){  // T1
    current=0;
}
  

И

 auto tmp = current.fetch_add(1);  // T1
long long cs=current;  // T2
current=tmp%4;  // T1
  

Решение заключается в использовании мьютексов или спин-блокировок с обменом сравнениями.

Ответ №2:

Это сценарий, который с большой вероятностью может произойти в многопоточной среде. Предположим, что только 2 потока, основной поток, который я назвал здесь THREAD-2, и рабочий поток THREAD-1. Давайте начнем с current, имеющего значение 3, и теперь оно увеличивается ПОТОКОМ-1, в то время как ПОТОК-2 обновляет переменную cs.

 THREAD-1:    current.fetch_add(1);
THREAD-2:    cs = current;
THREAD-1:    if(current>=4){ current=0; }
  

как вы можете видеть, cs получает это значение, когда current равно 4.

Кроме того, это не проблема objective-c, это только C .