Сравнение атомарных переменных в C - PullRequest
0 голосов
/ 15 ноября 2018

У меня есть 2 атомные переменные:

atomic_ulong overwrap_cnt = 0;
atomic_ulong overwrap_read_cnt = 0;

Один поток выполняет увеличение overwrap_cnt (один раз):

overwrap_cnt++;

Другой поток выполняет сравнение в бесконечном цикле:

while(1)
{
 if (overwrap_read_cnt == overwrap_cnt)
 {
  printf("or:%lu, ow:%lu \n",overwrap_read_cnt, overwrap_cnt);
 }
 usleep(100000);
}

Однако, результат всегда следующий:

or:0, ow:1
or:0, ow:1
or:0, ow:1

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

Не могу ли я сравнить атомарные переменные, как это? Или что не так?

Это на centos 7.5 с gcc (GCC) 4.9.2 20150212 (Red Hat 4.9.2-6)

Спасибо.

1 Ответ

0 голосов
/ 15 ноября 2018

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

Рассмотрим, например, если вы написали код с таким же поведением, используя атомарные встроенные функции GCC:

while(1)
{
  unsigned long _tmp1 = __atomic_load_n(&overwrap_read_cnt, __ATOMIC_RELAXED);
  unsigned long _tmp2 = __atomic_load_n(&overwrap_cnt, __ATOMIC_RELAXED);
  if (_tmp1 == _tmp2)
  {
    _tmp2 = __atomic_load_n(&overwrap_cnt, __ATOMIC_RELAXED);
    _tmp1 = __atomic_load_n(&overwrap_read_cnt, __ATOMIC_RELAXED);
    printf("or:%lu, ow:%lu \n", _tmp1, _tmp2);
  }
  usleep(100000);
}

Хотя значения, выбранные для сравнения, были определены как равные, они могут больше не совпадать с моментом их повторного вызова для вызова printf.

Если вы хотите убедиться, что значения, использованные позже, будутКак и в операторе if, вы должны получить их только один раз, а затем использовать кэшированные значения на протяжении всей итерации цикла.

...