Копирование при записи с помощью shared_ptr при многопоточности

В отсутствие многопоточности реализация копирования при записи для shared_ptr (либо из boost, либо из tr1) с использованием unique() проста. Какие изменения необходимо внести при многопоточности? Счетчик ссылок является атомарным, поэтому я предполагаю, что могу создавать, копировать-конструировать, читать и уничтожать экземпляры shared_ptr без дальнейших проблем. Как насчет их обновления в целом и особенно при реализации копирования при записи? Нужны ли замки? Или использовать boost::atomic_store (почему это не задокументировано)? Или ждать полностью атомарную версию shared_ptr (не вариант)?

Редактировать:
sfossen, спасибо за ваш полезный ответ.
Итак, я заключаю, что если я изменяю объект, на который указывает, только после его отсоединения через COW, так что им владеет только текущий поток, блокировка не требуется и реализация COW выглядит точно так же, как однопоточная при использовании shared_ptr с атомарными счетчиками ссылок.


person Community    schedule 05.03.2009    source источник
comment
да, если ни один другой поток не может его изменить, никаких проблем. например. В очереди заданий вы заблокируете очередь, чтобы удалить задание, но как только поток станет владельцем задания, вам не нужно снова блокировать его, пока не будет получено другое задание.   -  person sfossen    schedule 06.03.2009
comment
Отвечает ли это на ваш вопрос? Вы хотите, чтобы что-нибудь объяснили дальше?   -  person sfossen    schedule 06.03.2009


Ответы (2)


С COW вам нужна блокировка только при копировании объектов, которые могут находиться в процессе изменения.

Таким образом, если COW объекта является объектом, установленным до потоков и никогда не меняющимся, блокировка не требуется.

Однако, если вы делаете копии копий, вам необходимо, по крайней мере, заблокировать во время начальной записи или убедиться, что в копии есть все изменения, прежде чем ее можно будет скопировать снова.

Если вы не можете полностью гарантировать это, используйте блокировку или атомарные обновления.

Если вы хотите заблокировать:

Кажется, сейчас в багажнике есть атомарная версия.

Если вы не можете обновить boost, вы можете либо импортировать необходимые функции на данный момент, либо заключить их в блокировку, например блокировку чтения/записи.

из shared_ptr.hpp

template<class T> shared_ptr<T> atomic_exchange( shared_ptr<T> * p, shared_ptr<T> r )
{
    boost::detail::spinlock & sp = boost::detail::spinlock_pool<2>::spinlock_for( p );

    sp.lock();
    p->swap( r );
    sp.unlock();

    return r; // return std::move( r )
}

статья о RWLocks

person sfossen    schedule 05.03.2009

Небезопасно копировать shared_ptr без какой-либо формы синхронизации, если только он не принадлежит потоку, выполняющему копирование. Гарантии безопасности потока применяются только к shared_ptr, принадлежащим потоку, где внутренний счетчик ссылок shared_ptr может использоваться совместно с shared_ptr, принадлежащими другим потокам.

Поведение, которое вы хотите, заключается в том, что я бы назвал атомарно потокобезопасным, которого в настоящее время нет в shared_ptr и, вероятно, не будет даже после C++0x. Имя shared_ptr здесь, вероятно, немного сбивает с толку, поскольку вы не можете использовать shared_ptr между потоками без синхронизации.

person Community    schedule 08.03.2009