У статті з такою ж назвою, що й у цьому питанні, автори описують, як побудувати неблокуючу лінійну операцію з декількома словами CAS, використовуючи лише односкладне CAS. Вони спочатку запроваджують операцію подвійного порівняння-один-своп - RDCSS, наступним чином:
word_t RDCSS(RDCSSDescriptor_t *d) {
do {
r = CAS1(d->a2, d->o2, d);
if (IsDescriptor(r)) Complete(r);
} while (IsDescriptor(r));
if (r == d->o2) Complete(d); // !!
return r;
}
void Complete(RDCSSDescriptor_t *d) {
v = *(d->a1);
if (v == d->o1) CAS1(d->a2, d, d->n2);
else CAS1(d->a2, d, d->o2);
}
де RDCSSDescriptor_t
є структура з такими полями:
a1
- адреса першої умовиo1
- значення, очікуване за першою адресоюa2
- адреса другої умовиo2
- значення, очікуване за другою адресоюn2
- нове значення, яке потрібно записати на другу адресу
Цей дескриптор створюється та ініціалізується один раз у потоці, який ініціює операцію RDCSS - жоден інший потік не має посилання на нього, поки перший CAS1 у функції не стане RDCSS
успішним, роблячи дескриптор доступним (або активним у термінології статті).
Ідея алгоритму полягає в наступному - замініть друге місце пам'яті на дескриптор, який говорить, що ви хочете зробити. Потім, враховуючи, що дескриптор присутній, перевірте місце першого пам'яті, щоб побачити, чи змінилося його значення. Якщо цього немає, замініть дескриптор у другому місці пам'яті на нове значення. В іншому випадку поверніть друге місце пам'яті до старого значення.
Автори не пояснюють, чому рядок із !!
коментарем необхідний у статті. Мені здається, що CAS1
вказівки у Complete
функції завжди будуть провалюватися після цієї перевірки, за умови, що не буде одночасних змін. І якщо відбулася паралельна модифікація між чеком і CAS в Complete
, то потік, який здійснює перевірку, все-таки повинен провалюватися зі своїм CAS в Complete
, оскільки паралельна модифікація не повинна використовувати той самий дескриптор d
.
Моє питання: Чи можна перевірити в функції RDCSSS
, if (r == d->o2)...
буде опущений, з RDCSS зберігаючи семантику подвійного порівняння, однієї команди обміну , яка лінеарізуема і безблокіровочний ? (рядок із !!
коментарем)
Якщо ні, чи можете ви описати сценарій, коли цей рядок насправді необхідний для забезпечення коректності?
Дякую.