Boost:: shared_ptr безопасно использовать его в нескольких потоках?

Я пытался найти ответ в течение некоторого времени, но я потерпел неудачу.

Предположим, что у нас есть shared_ptr, созданный из одного потока. Затем мы передаем этот shared_ptr в другие 2 потока (например, используя некоторую очередь). Таким образом, с этого момента есть 2 копии оригинала shared_ptr, указывающие на один и тот же необработанный указатель. Оба потока владельца будут брать свои копии этого shared_ptr из очереди. Затем они передадут его в другой поток или уничтожат его.

Вопрос - это безопасно? Будет ли исходный указатель уничтожен правильно (не будет никакой гонки для счетчика?) enter image description here

Ответ 1

повысить документы:

Различные экземпляры shared_ptr могут быть "записаны на" (доступны с помощью изменяемых операций, таких как operator = или reset) одновременно несколькими потоками (, даже если эти экземпляры являются копиями и совместно используют подсчет ссылок ниже.)

(акцент мой)

Итак, суть здесь в том, скопируете ли вы boost::shared_ptr между потоками или нет. Если вы создаете копии ( "безопасный" способ использования shared_ptr s), у вас нет никаких забот о безопасности потоков. Если, однако, вы передаете shared_ptr по ссылке или указателю и, следовательно, используете фактический те же shared_ptr в разных потоках, вам придется беспокоиться о безопасности потоков, как описано в документах.

Ответ 2

В стандарте С++ практически нет гарантий безопасности потоков. Единственным исключением является счетчик ссылок std::shared_ptr: он гарантированно ведет себя как переменная с атомарным доступом. Я считаю, что это кодифицировано в этой фразе в §20.7.2.2/4:

Изменения в use_count() не отражают изменений, которые могут приводить к расам данных.

boost::shared_ptr предлагает те же гарантии:

Объекты

shared_ptr обеспечивают тот же уровень безопасности потоков, что и встроенные типы. Экземпляр shared_ptr может быть "прочитан"... одновременно несколькими потоками. Различные экземпляры shared_ptr могут быть "записаны на"... одновременно несколькими потоками (даже если эти экземпляры являются копиями и совместно используют тот же подсчет ссылок внизу.)

Ответ 3

Я хотел бы опубликовать свой комментарий для подсчета ссылок в объединенном указателе boost в случаях использования нескольких потоков. Комментарий состоит в том, чтобы ответить на вопрос, что "есть ли какое-либо условие гонки в подсчете ссылок на общий общий указатель?"

Мой простой ответ - "Нет", по крайней мере, после повышения 1.35 для большинства основных компиляторов. Функция boost, называемая add_ref_copy, определена в boost/detail/shared_count.hpp. Эта функция вызовет соответствующую атомную функцию, определенную для отдельного компилятора. Например, версия Windows вызовет "BOOST_INTERLOCKED_INCREMENT", чтобы увеличить счетчик по атомному пути (подробнее см. Подробности \sp_counted_base_w32.hpp). И Linux gcc для X86 вызовет atom_increment (...) (подробнее см. \Sp_counted_base_gcc_x86.hpp). Каждый отдельный компилятор реализовал механизм, оптимизирующий поток, чтобы обеспечить эффективное обновление счетчика ссылок. Некоторая часть кода написана даже в сборке.

Теперь в моем простом ответе есть оговорки. Вам действительно нужно убедиться, что ваш компилятор включен в расширенный список улучшений для множественного подсчета ссылок на потоки. Если вы не уверены, что можете определить "BOOST_SP_USE_PTHREADS", который стимулирует использование библиотеки pthread, чтобы сделать обновление счетчика ссылок атомарно (включив boost/detail/sp_counted_base_pt.hpp для решения pthread).