
![]() |
Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
|
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[216.73.217.4] |
![]() |
|
Страницы: (16) « Первая ... 10 11 [12] 13 14 ... Последняя » все ( Перейти к последнему сообщению ) |
Сообщ.
#166
,
|
|
|
Цитата Олег М @ Недостаточно просто создать объект, его ещё нужно потом и удалить. Т.е. создание объекта и контроль за временем его жизни две неразрывно связанные задачи. И если, после создания объекта мне будет необходимо впихивать его в какие-то контейнеры, а перед удалением оттуда его вытаскивать, вместо того, чтобы просто создать или присвоить переменную, то это как-то накладно получиться. Замучишься потом профилировать, где у тебя тормозит. А вот это всё от конкретных сценариев зависит. shared/weak_ptr - это сценарий, когда свет гасит последний уезжающий. Т. е. может быть сколько угодно ссылок на объекты в разных местах программы, когда последняя отваливается - объект удаляется. Удобно. Но не всегда. У тебя, если я всё правильно понимаю, вопросов с тем, когда именно создавать и удалять объект - нет. Создаётся объект тогда, когда совершается коннект к серверу, удаляется - при дисконнекте, ну или вскоре после. То есть создание/удаление неразрывно связано с состоянием определённого ресурса. Поэтому в этом случае возникает совсем другой вопрос: можно ли в данный конкретным момент пользоваться объектом? Именно поэтому ты пытаешься пользовать связку shared_ptr/weak_ptr. Ну, как я понимаю. Конкретно такой - нет. И даже причину назвал: его варианты использования не соответствуют требуемым тобою сценариям. А то, что соответствует, не является shared/weak_ptr'ом. |
Сообщ.
#167
,
|
|
|
Цитата Flex Ferrum @ . У тебя, если я всё правильно понимаю, вопросов с тем, когда именно создавать и удалять объект - нет. Создаётся объект тогда, когда совершается коннект к серверу, удаляется - при дисконнекте, ну или вскоре после. То есть создание/удаление неразрывно связано с состоянием определённого ресурса. Нет, у меня так решается масса задач, все в которых нужно хранить ссылку на объект, время жизни которого ты не контролируешь. Эта единственная, которую я мог внятно сформулировать. Цитата Flex Ferrum @ Поэтому в этом случае возникает совсем другой вопрос: можно ли в данный конкретным момент пользоваться объектом? Пользоваться - т.е. обращаться к содержимому указателя? До, но только в том случае, когда ты владеешь shared_ptr. Цитата Flex Ferrum @ Конкретно такой - нет. И даже причину назвал: его варианты использования не соответствуют требуемым тобою сценариям. А то, что соответствует, не является shared/weak_ptr'ом. Не соответствует в чём? Интерфейс вроде такой же, поведение тоже. Отличается только реализация. |
Сообщ.
#168
,
|
|
|
Цитата Олег М @ Не соответствует в чём? Не соответствует хотя бы тем, что тебе необходимо из разных потоков работать с одной копией сильного/слабого указателя. Просто вот этой вот самой необходимостью. Это означает, что ты не можешь раздать по потокам копии указателей на некую сущность и "забыть" про неё. Это означает, что несколько потоков контролируемо разделяют доступ к этой сущности, включая время жизни. Повторюсь: иначе всей этой возни бы не было. Попробуй написать хотя бы код своего примера так, чтобы он работал с таким вариантом объявления лямбд: ![]() ![]() threads.emplace_back(std::make_unique<std::thread>([sp, sp2, &stop]() // ... threads.emplace_back(std::make_unique<std::thread>([sp2, &stop]() // ... (как, собственно, и нужно использовать самарт-указатели согласно их контрактам) - и ты (я надеюсь) поймёшь, о чём я говорю. |
Сообщ.
#169
,
|
|
|
Цитата Flex Ferrum @ Не соответствует хотя бы тем, что тебе необходимо из разных потоков работать с одной копией сильного/слабого указателя. Это вопрос реализации класса, таких требований к нему нет. Видел, что я выше писал по поводу msdn? Цитата Flex Ferrum @ threads.emplace_back(std::make_unique<std::thread>([sp2, &stop]() // ... (как, собственно, и нужно использовать самарт-указатели согласно их контрактам) - и ты (я надеюсь) поймёшь, о чём я говорю. sp2 - это вроде weak_ptr. И что с ним делать во втором потоке, как не вызывать lock()? |
Сообщ.
#170
,
|
|
|
Таки попробуй переписать свой пример так, чтобы каждый поток использовал свою собственную копию указателя. Когда не получится - попробуй объяснить, почему не получилось, и зачем нужно иначе.
|
Сообщ.
#171
,
|
|
|
Смысл примера, в том, что один поток изменяет указатель, а второй делает с него копию. Собственно, это и есть то, для чего и сделаны эти классы. Что там переписывать?
Добавлено С таким же успехом можно сказать - сделай так, чтоб каждый поток использовал свою копию мьютекса |
Сообщ.
#172
,
|
|
|
Цитата Олег М @ Смысл примера, в том, что один поток изменяет указатель, а второй делает с него копию. Собственно, это и есть то, для чего и сделаны эти классы. Что там переписывать? Нет. Они не сделаны для этого. В том то и фишка. ![]() Представим себе такую ситуацию: ![]() ![]() std::string *sp; std::string **sp2; //CSharedPtr<std::string> sp; //CWeakPtr<std::string> sp2; volatile bool stop = false; std::list<std::unique_ptr<std::thread>> threads; threads.emplace_back(std::make_unique<std::thread>([&sp, &sp2, &stop]() { while(!stop) { sp = new std::string("!!!!!!!!!!!!!!!!!!!!!!!!!!!!11111111111111111111111111111111111111"; *sp2 = sp; } })); threads.emplace_back(std::make_unique<std::thread>([&sp2, &stop]() { int i = 0; while(!stop) { auto sp = *sp2; if (sp) std::cout << (++i) << ", " << *sp << std::endl; std::this_thread::sleep_for(10ms); } })); WaitStop(); stop = true; for (auto &item: threads) item->join(); Я убрал из твоего кода смарт-указатели, заменив их на обычные. Этот код корректен? Нет. Ты работаешь с разделяемым ресурсом (sp/sp2) без синхронизации. Ты имеешь здесь data race. unique_ptr/shared_ptr/weak_ptr/XXXPtr - все они имеют семантику указателя. Они ведут себя, как обычный указатель, by design. Соответственно, любая несихронизированная работа с ними из разных потоков - это нарушение контракта и семантики. Ну вот так вот. ![]() Добавлено Цитата Олег М @ С таким же успехом можно сказать - сделай так, чтоб каждый поток использовал свою копию мьютекса Вот. До тебя начинает доходить. У тебя есть разделяемый ресурс, от которого ты не можешь избавиться. И ты через этот ресурс обмениваешься данными между потоками. Значит, и контракт "обёртки" должен быть на это рассчитан. Не надо натягивать сову на глобус - ей больно. ![]() |
Сообщ.
#173
,
|
|
|
Задачи которые решают мьютексы и shared_ptr абсолютно симметричные. Разница состоит в том, что один блокирует кусок кода от доступа, второй блокирует объект от удаления. Больше принципиальных отличий я не вижу.
|
Сообщ.
#174
,
|
|
|
Цитата Олег М @ Задачи которые решают мьютексы и shared_ptr абсолютно симметричные. Разница состоит в том, что один блокирует кусок кода от, второй блокирует объект от удаления. Больше принципиальных отличий я не вижу. Это как с тем сусликом. Отличий ты, может, и не видишь. А они есть. Они в том, что mutex - это (по сути и дизайну) разделяемый между потоками ресурс. Ты имеешь в разных потоках одну и ту же копию мьютекса и работаешь именно с этой копией. А shared_ptr разделяет владение неким ресурсом между разными точками в программе. Сколько точек владения (копий shared_ptr'а) - такова величина счётчика. Но при этом (в отличие от мьютекса) точки владения работают независимо друг от друга. Представь, что ты работаешь не с shared_ptr, а с IUnknown и CComPtr. Объект, с интрузивным счётчиком. Каждый новый указатель на него (по контракту) должен счётчик увеличивать, разрушение указателя - уменьшать. Объект умрёт тогда, когда количество ссылок на него - 0. И это произойдёт в любом случае, сколько бы указателей (безссылочных) на него бы не висело. COM-объекты сами следят за временем своей жизни, на желания клиентов что-то там сделать в одном потоке и прочитать в другом им, в сущности, наплевать. Пришло время умирать - умерли. shared_ptr - то же самое, только счётчик экструзивный. Опять не ясно? Разделение владения между копиями указателя != разделение ресурса между потоками. И не может быть равно. |
Сообщ.
#175
,
|
|
|
Цитата Flex Ferrum @ Это как с тем сусликом. Отличий ты, может, и не видишь. А они есть. Они в том, что mutex - это (по сути и дизайну) разделяемый между потоками ресурс. Ты имеешь в разных потоках одну и ту же копию мьютекса и работаешь именно с этой копией. А shared_ptr разделяет владение неким ресурсом между разными точками в программе CSharedPtr это тоже разделяемый между потоками ресурс. Почему вдруг нет? Попробуй написать реализацию мьютекса, рекурсивного, - увидишь, что она будет очень похожа на реализацию CSharedPtr. |
Сообщ.
#176
,
|
|
|
Цитата Олег М @ CSharedPtr это тоже разделяемый между потоками ресурс. Почему вдруг нет? Так а тебе что нужно то на самом деле? Разделяемый между потоками ресурс или разделяемый между точками владения контроль времени жизни? Судя по всему - первое. А ты топишь за второе. ![]() |
Сообщ.
#177
,
|
|
|
Цитата Flex Ferrum @ Разделяемый между потоками ресурс или разделяемый между точками владения контроль времени жизни? Вместо "или" поставь "и", тогда будет правильно. Кстати, довольно распространённая ошибка. |
Сообщ.
#178
,
|
|
|
Цитата Олег М @ Вместо "или" поставь "и", тогда будет правильно. Кстати, довольно распространённая ошибка. В таком случае возвращаемся к: Цитата Flex Ferrum @ Тебе нужен что-то в стиле RemoteObjectHolder. Это не столько указатель, сколько сервисный класс, контролирующий доступ к объекту из разных потоков, его операбельность и прочие подобные фишки. Потому что гибрид ежа с ужом - это, в целом, не очень хорошая идея. Если ты делаешь точку обмена данными между потоками (а ты делаешь именно её) - то ты должен вносить соответствующие элементы дизайна в интерфейс. Потому что ты делаешь точку обмена данными, у тебя задача такая. Задачу контроля времени жизни ты всё равно решишь. Но, вполне вероятно, совсем не так, как это делает shared_ptr. Хотя бы потому, что контролировать время жизни ресурса ты будешь методами, отличными от счётчика ссылок. И передача владения объектом из потока в поток у тебя может получиться явной, а не "под ковром". В общем, тут пока тот случай, что микроскоп, конечно, достаточно тяжёл, чтобы им гвозди забивать. Но таки лучше взять молоток. |
Сообщ.
#179
,
|
|
|
Цитата Flex Ferrum @ Если ты делаешь точку обмена данными между потоками (а ты делаешь именно её) - то ты должен вносить соответствующие элементы дизайна в интерфейс. Потому что ты делаешь точку обмена данными, у тебя задача такая. Задачу контроля времени жизни ты всё равно решишь. Вроде ж решил. CSharedPtr - это не ресурс, это указатель на ресурс. Что за элементы дизайна? Конструктор копирования и weak_ptr::lock это не они? |
Сообщ.
#180
,
|
|
|
Цитата Олег М @ Вроде ж решил. CSharedPtr - это не ресурс, это указатель на ресурс. Что за элементы дизайна? Конструктор копирования и weak_ptr::lock это не они? Ну так у тебя "указатель на ресурс" и является разделяемым ресурсом (такой вот каламбур), точкой обмена данными, посредством которой некий объект попадает из одного потока в другой. |