Итак, пока мы знаем, что двойная проверка блокировки как есть не работает в C ++, по крайней мере, не в переносимой форме.
Я только что понял, что у меня хрупкая реализация в ленивом дереве, которое я использую для трассировки лучей местности. Поэтому я попытался найти способ все еще использовать ленивую инициализацию безопасным способом, поскольку я не хотел бы в четыре раза использовать память и переупорядочивать большие части реализованных алгоритмов.
Это прохождение вдохновлено шаблоном на странице 12 C ++ и опасностями двойной проверки блокировки , но пытается сделать это дешевле:
(pseudo code!)
struct Foo {
bool childCreated[4];
Mutex mutex[4];
Foo child[4];
void traverse (...) {
...
if (!childCreated[c]) {
// get updated view
#pragma flush childCreated[c]
if (!childCreated[c]) {
ScopedLock sl (mutex[c]);
if (!childCreated[c]) {
create (c);
#pragma flush childCreated[c]
childCreated[c] = true;
}
}
}
}
}
Предполагается, что #pragma flush
также будет служить жесткой последовательностью, когда компиляторам и процессорам не будет разрешено переупорядочивать операции между ними.
Какие проблемы вы видите?
изменить: Версия 2, пытаясь учесть ответ Владис (ввести третий сброс):
(pseudo code!)
struct Foo {
bool childCreated[4];
Mutex mutex[4];
Foo child[4];
void traverse (...) {
...
if (!childCreated[c]) {
// get updated view
#pragma flush childCreated[c]
if (!childCreated[c]) {
ScopedLock sl (mutex[c]);
#pragma flush childCreated[c]
if (!childCreated[c]) {
create (c);
#pragma flush childCreated[c]
childCreated[c] = true;
}
}
}
}
}
edit: Версия 3, я как-то нахожу это довольно эквивалентным Версии 2, потому что я использую не дочерний элемент, а примитивный флаг для проверки на допустимость, в основном полагаясь на барьер памяти между ребенок и писать под этим флагом.
(pseudo code!)
struct Foo {
bool childCreated[4];
Mutex mutex[4];
Foo child[4];
void traverse (...) {
...
if (!childCreated[c]) {
ScopedLock sl (mutex[c]);
#pragma flush childCreated[c]
if (!childCreated[c]) {
create (c);
#pragma flush childCreated[c]
childCreated[c] = true;
}
}
}
}