2010-03-26 4 views
6

В boost::shared_ptr деструктора, это делается:Почему контрольный счетчик в boost :: shared_ptr нестабилен?

if(--*pn == 0) 
{ 
    boost::checked_delete(px); 
    delete pn; 
} 

где pn является указателем счетчика ссылок, который typedefed в

shared_ptr::count_type -> detail::atomic_count -> long 

Я бы ожидал, что long быть volatile long, учитывая поточное использование и неатомное 0-check-and-deletion в деструкторе shared_ptr выше. Почему он не изменчив?

EDIT:

Оказывается, я посмотрел на заголовок, используемый при многопоточной использование не указано (atomic_count.hpp). В atomic_count_win32.hpp декремент правильно реализован для многопоточного использования.

+0

Где вы находите этот код кстати? – jalf

+0

@jalf: shared_ptr_nmt.hpp –

ответ

16

Потому что volatile не требуется для многопоточности и не приносит ничего полезного, но потенциально разрушает ряд оптимизаций.

Для обеспечения безопасного многопоточного доступа к переменной примитив, который нам нужен, является барьером памяти, который обеспечивает как гарантию volatile, так и несколько других (это предотвращает переупорядочение доступа к памяти через барьер, do)

Я считаю, что shared_ptr использует атомные операции, когда это возможно, что неявно обеспечивает барьер памяти. В противном случае он возвращается к мьютексу, что также обеспечивает барьер памяти.

См Why is volatile not considered useful in multithreaded C or C++ programming? или http://software.intel.com/en-us/blogs/2007/11/30/volatile-almost-useless-for-multi-threaded-programming/ для получения более подробной информации

Редактировать
count_type является неlong в общем случае. Это кабриолет до long. Если вы посмотрите в atomic_count.hpp, typedef to long применяется, только если потоковая передача недоступна (в этом случае, конечно, синхронизация не требуется). В противном случае он использует реализацию, определенную в boost/smart_ptr/detail/atomic_count_pthreads.hpp или boost/smart_ptr/detail/atomic_count_win32.hpp, или один из других перечисленных файлов. И это синхронизированные классы-оболочки, которые гарантируют, что все операции выполняются атомарно.

+0

«Я считаю, что shared_ptr использует атомарные операции, когда это возможно» - не в моем цитированном примере с деструктором, в котором сейчас находится моя проблема ... –

+0

Ну, если бы переменная 'volatile' ничего не изменила бы. Вы правы, уменьшая и сравнивая длинный против нуля, кажется опасным, но это зависит от того, что делает * rest * класса указателя. – jalf

+0

@jalf: Это ты потерял меня.;-) Прямо сейчас, в моем примере, два потока входят в shared_ptr dtor, а «остальная часть класса указателя» ничего не делает. –

8

volatile не имеет ничего общего с резьбой. См. here.

+0

Не могли бы вы сказать, что с обработкой счетчика в деструкторе нет проблем с обработкой в ​​разных потоках? –

2

Вы неправильно читаете код. atomic_count определяется просто как длинный, если код не использует многопоточность:

#ifndef BOOST_HAS_THREADS 

namespace boost 
{ 

namespace detail 
{ 

typedef long atomic_count; 

} 

} 

#elif //... include various platform-specific headers that define atomic_count class 

#endif 
+0

Спасибо! Отредактировал вопрос, чтобы прояснить ситуацию. (Уже принял ответ jalf) –

Смежные вопросы