Назначение возвращаемого значения атомарной функции

Я пытаюсь реализовать функцию барьера, так что когда поток вызывает waitBarrier() это будет ждать, пока все остальные n Потоки вызвали функцию, после которой все будет продолжаться, то есть своего рода конструкция синхронизации.

У меня есть следующий код:

int i = 0; // Shared variable. Initialized as 0 at the beginning.

waitBarrier() {

  // CAS = Compare-and-swap, the first argument holds "old_val" the second the new
  i = CAS(i, i+1);

  // Spin until all n threads (number of all threads known prior) have been "here"
  while (i != n) {}

}

Если к этому получит доступ n темы, будет ли эта функция работать? Является ли присвоение возвращаемого значения атомарной функции атомарным? Или могут возникнуть условия гонки?

1 ответ

Решение

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

CAS(int* reg, int oldValue, int newValue)

или же

reg.CAS(int oldValue, int newValue)

Предполагая, что ваша строка сейчас будет:

i = i.CAS(i, i+1)

Представьте, что два потока вызывают waitBarrier() в то же время. Предполагая, что аргументы атомарной функции оцениваются неатомно, то есть оба потока на самом деле i.CAS(0,1)

Кто бы ни выполнял атомарный вызов первым, он успешно установит общую переменную i в 1. Поскольку CAS всегда возвращает старое значение, имея назначение i = OLD_VALUE_OF_i вы на самом деле сбрасываете переменную общего доступа обратно на 0. Не только это, но и представьте, что вы полностью опустили бы это назначение и просто сделали вызов CAS, кто бы ни выполнял поток, выполняющий CAS секунду, будет сравнивать значение общего значения (которое теперь будет равно 1) с начальным значением i (во время оценки аргументов, которое было 0), которое завершится ошибкой, и, следовательно, общая переменная будет увеличена только один раз!

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

int i = 0;

waitBarrier() {
  // Atomically increment the shared value i by 1
  do {
    int value = i;
  } while (CAS(i, value, value + 1));

  // Wait until all threads have passed the barrier
  while (i != n) {}
}
Другие вопросы по тегам