Как использовать двойную проверку блокировки для инициализации shared_ptr

(Предполагая, что VC ++ 2010: (1) может использовать / volatile: мс, (2) пока нет std :: atomic, (3) нет инициализации статической переменной, безопасной для потока, (4) нет std :: call_once)

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

static volatile void * ptr = nullptr;

//...
if ( ptr == nullptr)
{
// Acquire Lock
if (ptr == nullptr)
{
// some code
// ptr = ...; // init ptr
}
// Release Lock
}
// ....

Начиная с VC ++ 2005 volatile проверяет правильность приведенного выше кода. Предположим, я в порядке с кодом не переносимым.

Теперь предположим, что мне нужно заменить простой указатель на std :: shared_ptr или boost :: shared_ptr, как мне сделать то же самое? Как сделать этот shared_ptr изменчивым? Нужен ли мне другой нестабильный флаг?

0

Решение

В C ++ 11 есть атомарные функции доступа для shared_ptr, Чтобы написать дважды проверенный замок, который использует shared_ptrиспользуйте эти средства доступа:

static std::shared_ptr<MyType> ptr;
if (std::atomic_load(ptr) == 0) {
// lock the lock
if (std::atomic_load(ptr) == 0) {
std::shared_ptr<MyType> local_ptr(new MyType);
std::atomic_store(ptr, local_ptr);
}
// unlock the lock
}
return ptr;
4

Другие решения

Начиная с VC ++ 2005 volatile проверяет правильность приведенного выше кода.

Нет. volatile не имеет ничего общего с многопоточностью или атомарностью.

Ваш текущий код неверен и не гарантируется каким-либо стандартом C ++ для обеспечения разумного поведения.

Так как ваш код с притворной блокировкой вообще не работает, он определенно не будет работать на shared_ptr или другие умные указатели. Если вы хотите более дешевую блокировку, посмотрите на шаблоны кодирования без блокировки.

3

В C ++ 2011 его даже не нужно использовать любой объяснять синхронизацию. В соответствии с 6.7 [stmt.dcl] параграф 4 инициализация синхронизируется системой:

Если во время инициализации переменной элемент управления вводит объявление одновременно, параллельное выполнение должно ожидать завершения инициализации.

Это, кажется, подразумевает, что std::shared_ptr<T> можно инициализировать так:

{
static std::shared_ptr<MyType> ptr(new MyType(/*...*/));
// ...
}
1
По вопросам рекламы [email protected]