Можно ли иногда звонить create_lazy
более одного раза?Если это так, то это очень легкое и эффективное решение, использующее только TBB:
tbb::atomic<LAZY*> lazy;
if(!lazy)
{
LAZY *newlazy = create_lazy();
if(lazy.compare_and_swap(newlazy, 0))
{
// lazy was initialized elsewhere.
delete newlazy;
}
}
// use lazy.
Это будет иметь намного меньше (ноль!) Издержек, чем решение Maciej, но опять-таки будет работать только в том случае, если будет нормально иногда звонить create_lazy
более одного раза в случае возникновения разногласий между потоками по этой конкретной переменной.
Один из способов избежать как взаимного исключения, так и вызова create_lazy
более одного раза - это использовать спин-цикл.Это будет использовать больше ЦП, чем мьютекс, если есть конфликт, но все равно будут низкие накладные расходы:
tbb::atomic<LAZY*> lazy;
static int sentry;
if(!lazy && !lazy.compare_exchange((LAZY*)&sentry, 0))
{
// lazy is set to a sentry value while being allocated.
try{ lazy = create_lazy(); }
catch(...) { lazy = 0; throw; }
}
else
{
// yield the thread while lazy is still set to the sentry.
while(lazy == (LAZY*)&sentry)
{
tbb::this_tbb_thread::yield();
}
}
// use lazy.