Почему счетчик ссылок в boost :: shared_ptr не изменчив? - PullRequest
6 голосов
/ 26 марта 2010

В деструкторе boost::shared_ptr это сделано:

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

где pn - указатель на счетчик ссылок, который определен как

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

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

EDIT:

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

Ответы [ 3 ]

16 голосов
/ 26 марта 2010

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

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

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

См. Почему volatile не считается полезным в многопоточном программировании на C или C ++? или http://software.intel.com/en-us/blogs/2007/11/30/volatile-almost-useless-for-multi-threaded-programming/ для получения более подробной информации

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

8 голосов
/ 26 марта 2010

volatile практически не имеет ничего общего с потоками. Смотри здесь .

2 голосов
/ 26 марта 2010

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

#ifndef BOOST_HAS_THREADS

namespace boost
{

namespace detail
{

typedef long atomic_count;

}

}

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

#endif
...