Изменено: Ripper, 02 Апрель 2012 - 17:06
Разделяемый умный указатель с свистелками
#1 Опубликовано 02 Апрель 2012 - 17:05
#2 Опубликовано 03 Апрель 2012 - 5:14
Других указателей не осталось? Откуда тогда взять адрес объекта, если на него никто не указывает?других read-only указателей не осталось, объект просто достаётся ему, в противном случае делается копия.
И это очень странно, что может достаться копия, а может не копия. Это значит, что твоему классу скорее всего вообще никогда не надо менять объект.
Кроме того, важный вопрос говорим ли мы о многопоточной программе. Я так понимаю, что да. Смотри на std::mutex из C++11 или boost::mutex,если у тебя старый компилятор.
#3 Опубликовано 03 Апрель 2012 - 5:43
У пользователя уже есть read-only указатель, и если при этом других указателей на объект не существует, то пользователь может сделать из него read-write без копирования.Других указателей не осталось? Откуда тогда взять адрес объекта, если на него никто не указывает?
Объект - это какие-то данные, вроде изображения. Насколько мне известно, ничто похожее есть в php при копировании переменных (они фактически не копируются, а ссылаются на одни и те же данные до тех пор, пока какая-то из ссылающихся переменных не будет изменена).
#4 Опубликовано 03 Апрель 2012 - 7:09
Intrusive reference counter есть в бусте ( http://www.boost.org...rusive_ptr.html ), мы же пользуемся кастомным удалятором в boost::shared_ptr, т.е. своим указателем, который внутри хранит shared_ptr, который в деструкторе зовёт метод объекта на который указывает, а тот уже решает удаляться или нет.
boost::shared_ptr поддерживает многопоточность, но всяко если предполагается несколько потоков надо код мутатора защищать.
#5 Опубликовано 03 Апрель 2012 - 7:33
#6 Опубликовано 03 Апрель 2012 - 7:48
As we all know, the First Amendment to the C++ Standard states: "The committee shall make no rule that prevents C++ programmers from shooting themselves in the foot."На мой взгляд, получается сложно.
отсюда: http://thbecker.net/...section_04.html
Ну и да, зависит от типичного размера изображения и области применения всего этого чуда.
Ещё по теме: исходная задача неуловимо напоминает http://en.wikipedia....ers–writer_lock.
Изменено: St.ALKer, 03 Апрель 2012 - 8:23
#7 Опубликовано 03 Апрель 2012 - 8:26
Конечно. Я знаю, что речь идет о потоковом наложении эффектов на видео. Но что-то мне подсказывает, что в данном случае Паел хочет сделать преждевременную оптимизацию.As we all know, the First Amendment to the C++ Standard states: "The committee shall make no rule that prevents C++ programmers from shooting themselves in the foot."
отсюда: http://thbecker.net/...section_04.html
Ну и да, зависит от типичного размера изображения и области применения всего этого чуда.
Кстати, есть еще очень любопытный момент: синхронизация потоков. Синхронно ли работают различные этапы конвеера. Если нет, то как делается синхронизация на слиянии. Если да, то может быть вообще можно применить классический вариант с двойной буферизацией.
#8 Опубликовано 03 Апрель 2012 - 13:47
Именно об этом. Пример по ссылке проверяет количество ссылок перед копированием, так что именно это я и искал.Насколько я понимаю ты говоришь о чём-то типа copy on write ( http://en.wikibooks....s/Copy-on-write ), который по слухам применяется в некоторых реализациях std::string.
Единственно, что выглядит подозрительно - это то, что одна
Почему-то идея делать их Immutable мне в голову не пришла. Спасибо. Впрочем, не все фильтры обрабатывают каждый пиксел кадра. Кроме того, даже если фильтр обрабатывает кадр попиксельно, оверхед по оперативке, наверное, может существенно сказаться на производительности.На мой взгляд, получается сложно. Да, можно так написать, даже будет работать.
Но качество кода будет выше, если Ripper не будет экономить оперативку и будет считать свои изображения immutable. Если он собирается применять к изображению фильтр, то скорее всего все равно будет обрабатывать каждый пиксел кадра. И затраты по времени будут те же самые, как если этот кадр сохранять в то же самое место. Зато можно будет обойтись простым shared_ptr.
Заодно все методы работы с этим изображением станут thread safe, так как они будут константными.
Пожалуй, да. Просто оптимизированный вариант придумался раньше тривиального.преждевременную оптимизацию.
Работают асинхронно. Между фильтрами буфер вроде посоветованного тут (http://304.ru/index....ndpost&p=181227).Кстати, есть еще очень любопытный момент: синхронизация потоков. Синхронно ли работают различные этапы конвеера. Если нет, то как делается синхронизация на слиянии. Если да, то может быть вообще можно применить классический вариант с двойной буферизацией.
Единственное многопоточное место - этот буфер.
#9 Опубликовано 03 Апрель 2012 - 13:59
Насколько я понял, это лучше CowPtr только меньшим числом задействованных объектов (shared_ptr, CowPtr, Объект - против - intrusive_ptr, Объект).Но только ты ещё хочешь контролировать количество клиентов. В таком случае, если есть код самого объекта, ты можешь встроить счётчик ссылок туда (intrusive reference counter, http://en.wikibooks....ms/Counted_Body ), из мутаторов возвращать новый указатель, а решать копировать ли объект будет код мутатора - если refcount == 1, то мутировать in-place, если > 1 - клонировать и вызвать тот же метод. Тут конечно плохо, что надо не забыть сохрнить возвращённый указатель.
Изменено: Ripper, 03 Апрель 2012 - 14:00
#10 Опубликовано 03 Апрель 2012 - 14:00
Просто не надо хрранить умные указатели в умных указателях.Именно об этом. Пример по ссылке проверяет количество ссылок перед копированием, так что именно это я и искал.
что теоретически когда-нибудь может возникнуть необходимость сделать shared_ptr<CowPtr<...> >
А как потребление памяти влияет на производительность? При условии, что памяти хватает и ты не лезешь в своп. В кэш процессора у тебя несколько видеокадров все равно не поместятся. Аллокаций памяти будет больше, но я не думаю, что эьто сущетсвенно повлияет на производительность. В крайнем случае, можно ускорить саму алокацию буферов пользуясь тем, что они у тебя будут фиксированных размеров. Простейший список пустых буферов будет работать весьма эффективно.Кроме того, даже если фильтр обрабатывает кадр попиксельно, оверхед по оперативке, наверное, может существенно сказаться на производительности.
То есть тебя устроит, если один поток идет с камеры с 25 fps, а другой читается с диска с той скоростью, с которой машина может, а на выходе ты их смешиваешь и либо имеешь огромный плавающий fps не синхронизированных потоков, либо у тебя неограниченно растет буфер неотправленных кадров и забивает всю оперативку.Работают асинхронно. Между фильтрами буфер вроде посоветованного тут (http://304.ru/index....ndpost&p=181227).
Единственное многопоточное место - этот буфер.
Должна быть какая-то обратная связь, не позволяющая пропихнуть в конвеер очередной кадр, если он туда не лезет. Сделать такую можно, например, с помощью std::condition_variable. И тогда, в простейшем случае, ты можешь обойтись двумя буферами на каждую связь: в один пишем, из другого читаем. Когда данные прочитаны, а новые записаны, меняем буферы местами. Получаем фиксированное потребление памяти.
Ну или там может быть более ёмкий буфер, позволяющий накапливать несколько кадров. Посмоти на boost::circular_buffer.
#11 Опубликовано 03 Апрель 2012 - 14:24
Я вот и боюсь, что необходомость может возникнуть.Просто не надо хрранить умные указатели в умных указателях.
Будет в два раза больше обращений к памяти (в кэше нужно будет хранить больше данных на операцию, кусок кадра, помещающийся в кэше станет меньше). А список пустых буферов я уже сам придумал Буду пользоваться кастомным удалятором в shared_ptr'е.А как потребление памяти влияет на производительность? При условии, что памяти хватает и ты не лезешь в своп. В кэш процессора у тебя несколько видеокадров все равно не поместятся. Аллокаций памяти будет больше, но я не думаю, что эьто сущетсвенно повлияет на производительность. В крайнем случае, можно ускорить саму алокацию буферов пользуясь тем, что они у тебя будут фиксированных размеров. Простейший список пустых буферов будет работать весьма эффективно.
У меня придумана хитрая штуковина с привязкой данных ко времени, которая обеспечивает большую гибкость и некоторые бонусы.То есть тебя устроит, если один поток идет с камеры с 25 fps, а другой читается с диска с той скоростью, с которой машина может, а на выходе ты их смешиваешь и либо имеешь огромный плавающий fps не синхронизированных потоков, либо у тебя неограниченно растет буфер неотправленных кадров и забивает всю оперативку.
Должна быть какая-то обратная связь, не позволяющая пропихнуть в конвеер очередной кадр, если он туда не лезет.
Уже Я его и собирался использовать.Посмоти на boost::circular_buffer.
Изменено: Ripper, 03 Апрель 2012 - 14:25
#12 Опубликовано 03 Апрель 2012 - 14:42
У тебя объект скопировать быстрее, чем таскать умный указатель на него. Значит ты ничего не выиграешь по производительности.Я вот и боюсь, что необходомость может возникнуть.
У тебя указатель и так умный, значит ты ничего не выиграешь по функционалу.
Обращений к памяти будет одинаковое количество. У тебя фильтр сколько раз читает один пиксел из кадра? Если один, то кэш тебе никак не поможет. А если несколько раз (как например для blur'а), то ты не можешь писать обработанные данные поверх необработанных.Будет в два раза больше обращений к памяти (в кэше нужно будет хранить больше данных на операцию, кусок кадра, помещающийся в кэше станет меньше).
Главное глобальных часов не делай и текущее системное время не используй. А то ни протестировать не сможешь, ни в offline режиме запустить.У меня придумана хитрая штуковина с привязкой данных ко времени, которая обеспечивает большую гибкость и некоторые бонусы.
#13 Опубликовано 03 Апрель 2012 - 16:20
У тебя указатель и так умный, значит ты ничего не выиграешь по функционалу.
CowPtr не наследует возможности shared_ptr делать несколько указателей (полноценных, не const) на один объект. Потенциальный выигрыш именно в этом.одна
КороваCowPtr всегда связан с собственным состоянием объекта, то есть чтобы из двух мест работать с одним состоянием, нужно ссылаться на один CowPtr.
Некоторое время можно обходиться ссылками на один CowPtr, но, теоретически, когда-нибудь ссылок будет недостаточно и потребуются разделяемые указатели.
Изменено: Ripper, 03 Апрель 2012 - 16:20
#14 Опубликовано 03 Апрель 2012 - 18:34
А тебе это зачем надо? По ногам стрелять? shared_ptr, кстати, по возможности лучше не использовать. В большинстве ситуаций можно обойтись без них и получается проще.CowPtr не наследует возможности shared_ptr делать несколько указателей (полноценных, не const) на один объект. Потенциальный выигрыш именно в этом.
Внутри одного потока, в методы обработки, передавай вообще ссылку. Им же не надо владеть объектом.
А как только у тебя будет доступ на запись к объекту, про который знают другие потоки и он не защищен мьютексом, ты ощутишь всю мощь граблей. Причем скорее всего детских, с короткой рукояткой.
P.S. А знаетели вы, что в C++03
{
scoped_lock(mutex);
var = 10;
}
компилятор имеет право сначала разблокировать мьютекс, а потом записать 10 с регистра в память. Правда разработчики компиляторов таких идиотских оптимизаций стараются не делать.
1 пользователей читают эту тему
0 пользователей, 1 гостей, 0 невидимых