2010-04-21 2 views
6

У меня есть поток A, который выделяет память и назначает ее совместно используемому указателю. Затем этот поток генерирует 3 других потока X, Y и Z и передает копию общего указателя на каждый. Когда X, Y и Z выходят за рамки, память освобождается. Но есть ли вероятность того, что 2 потока X, Y выйдут из области видимости в тот же момент времени, и есть условие гонки на счетчике ссылок, вместо того, чтобы декрементировать его на 2, он только уменьшается один раз. Итак, теперь счетчик ссылок уменьшается до 0, поэтому происходит утечка памяти. Обратите внимание, что X, Y и Z считывают только память. Не записывать и не восстанавливать общий указатель. Короче говоря, может быть состояние гонки на счетчике ссылок и может ли это привести к утечкам памяти?Boost Shared Pointer: одновременный доступ для чтения через несколько потоков

+0

Интересно, что два человека использовали одну и ту же документацию для достижения противоположных выводов. –

+0

@Mark: Я бы сказал, что документы не совсем кристально чисты (не сказать, что они ошибаются, просто они легко ошибочно интерпретируются). –

+0

Я не понимаю, почему у вас есть щедрость на ваш вопрос.Ответ уже есть :) –

ответ

2

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

Для абсолютно неопровержимого доказательства см., Как Boost Smartptr фактически реализует свои собственные мьютексы с нуля в boost/smart_ptr/detail/sp_counted_base_gcc_x86.hpp (или соответствующий файл вашей платформы).

6

Нет, в соответствии с the documentation, эти проблемы не могут возникнуть:

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

+0

У меня есть вопрос: согласитесь с документацией, смешанная ситуация может привести к неопределенным beahvior: (...) // --- Пример 4 --- // нить A p3 = p2; // читает p2, p3 пишет // поток B // p2 выходит из области видимости не определено, деструктор считается «доступ на запись» (...) не мы в этой ситуации здесь? – Grimmy

+0

Пример ниже показывает поведение как «неопределенное», когда оно выходит за рамки. –

+1

@Grimmy, @Brian: В моем понимании в примере 4 в документации один поток пытается прочитать переменную 'shared_ptr', живущую в другом потоке, в то время как эта переменная выходит за рамки. Это будет неопределенным (и оно также будет неопределенным для других типов переменных, а не только для 'shared_ptr'). Если каждый поток получает свою собственную копию переменной shared_ptr, эти переменные могут использоваться (и выходить за рамки) независимо, даже если они указывают на один и тот же объект (как в примере 2 в документации). – sth

12

boost::shared_ptr использует блокировки (или блокировки свободного атомарного доступа), чтобы гарантировать, что счетчики ссылок обновляются атомарно (даже если это не ясно из страницы документов). Вы можете настроить использование блокировок, если вы пишете однопоточный код, определяя макрос BOOST_SP_DISABLE_THREADS.

Обратите внимание, что примеры документации в http://www.boost.org/doc/libs/1_42_0/libs/smart_ptr/shared_ptr.htm#ThreadSafety, в которых обсуждаются проблемы, связанные с несколькими записями из разных потоков обсуждает эти темы, действующие на одних и тех же shared_ptr случаях (в shared_ptr объекты могут быть Глобалы в примерах), а не различные shared_ptr копии, которые указывают на тот же объект, который является обычным прецедентом для shared_ptr. Пример, который вы задаете в вопросе (действующий на копии, указывающие на общий объект), является потокобезопасным.

+0

Комментарий точно правильный, но я бы также добавил, что вызов деструктора некоторых объектов из «неправильного» потока или «неправильного» времени может создавать обычные виды многопоточных ошибок, таких как расы и тупики. Если уничтоженный объект освобождает память, это не должно быть проблемой. Однако деструкторы, которые делают такие вещи, как дезактивация обреченного объекта другими компонентами системы, могут определенно вызвать проблемы. – Doug

+0

@Doug, который не имеет ничего общего с 'shared_ptr'. Лучше думать с точки зрения заблокированного эксклюзивного доступа, чем «он разбился, потому что он был не в том месте в неподходящее время». Какими бы ни были ресурсы, доступ к деструкторам должен блокироваться. – Potatoswatter

+0

@Potatoswatter: Да, я понимаю, что проблема, которую я поднял, напрямую не связана с безопасностью потока shared_ptr. Я не думаю о гоночных условиях, поскольку «это было не в то место в неподходящее время». Я нашел ошибки, вызванные shared_ptrs, которые потеряли свою последнюю ссылку (скажем) на не основной поток и где деструктор выполняет нетривиальную очистку. Это точно так же, как удаление указателя вручную, хотя - «такая же безопасность потока, как и исходные указатели», как указано в документации. – Doug

1

documentation говорит:

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

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

-2

Лучше всего было бы перейти на TR1 или C++ 0x shared_ptr, в отличие от разнообразия Boost. Я считаю, что стандартизировано, что они ДОЛЖНЫ быть потокобезопасными.

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