(Предполагая, что 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 изменчивым? Нужен ли мне другой нестабильный флаг?
В 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;
Начиная с VC ++ 2005 volatile проверяет правильность приведенного выше кода.
Нет. volatile
не имеет ничего общего с многопоточностью или атомарностью.
Ваш текущий код неверен и не гарантируется каким-либо стандартом C ++ для обеспечения разумного поведения.
Так как ваш код с притворной блокировкой вообще не работает, он определенно не будет работать на shared_ptr
или другие умные указатели. Если вы хотите более дешевую блокировку, посмотрите на шаблоны кодирования без блокировки.
В C ++ 2011 его даже не нужно использовать любой объяснять синхронизацию. В соответствии с 6.7 [stmt.dcl] параграф 4 инициализация синхронизируется системой:
Если во время инициализации переменной элемент управления вводит объявление одновременно, параллельное выполнение должно ожидать завершения инициализации.
Это, кажется, подразумевает, что std::shared_ptr<T>
можно инициализировать так:
{
static std::shared_ptr<MyType> ptr(new MyType(/*...*/));
// ...
}