Назначение возвращаемого значения атомарной функции
Я пытаюсь реализовать функцию барьера, так что когда поток вызывает 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) {}
}