Russian Qt Forum
Июнь 11, 2024, 03:30 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: 1 [2]   Вниз
  Печать  
Автор Тема: Manager + shared  (Прочитано 10970 раз)
Racheengel
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2679


Я работал с дискетам 5.25 :(


Просмотр профиля
« Ответ #15 : Август 20, 2016, 21:43 »

Цитировать
Есть одна система управления/ownership  (менеджер). Вы предлагаете добавить еще другую (parent-child).. Это будет работать только в случае m_parent == manager. Тогда зачем заводить m_parent, slaveKilled и.т.п. если можно действовать через тот же синглтон

Это не другая система, а гарантия того, что будет корректно работать "убивание" объектов не через менеджер.
Естественно, m_parent == manager - это основное для этого условие.
m_parent не должен быть указателем на класс менеджера, он может просто указывать на интерфейс типа IManager, у которого есть метод  типа IManager::OnObjectDestroyed(IObject* obj).
Тогда никакой синглтон не нужен. Тем более, в этом случае менеджеров может быть и несколько, не обязательно один Улыбающийся
Записан

What is the 11 in the C++11? It’s the number of feet they glued to C++ trying to obtain a better octopus.

COVID не волк, в лес не уйдёт
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #16 : Август 21, 2016, 08:09 »

Ага, все получается, причем совсем несложно
Код
C++ (Qt)
struct SkeletonManager {
typedef std::shared_ptr<Skeleton> TShared;
typedef std::weak_ptr<Skeleton> TWeak;
 
bool AddSkeleton( const std::string & key, Skeleton * sk )
{
// check already in map and alive
TMap::iterator it = mMap.find(key);
if (it != mMap.end())
if (!it->second.second.expired())
return false;
 
// create shared + weak
TPair & p = mMap[key];
p.first.reset(sk);
p.second = TWeak(p.first);
return true;
}
 
bool DeleteSkeleton( const std::string & key )
{
TMap::iterator it = mMap.find(key);
if (it == mMap.end()) return false;
TPair & p = it->second;
 
// release shared
if (p.first.get())      
p.first.reset();
 
// get rid pf empty slot
if (p.second.expired())
mMap.erase(it);
 
return true;
}
 
TWeak GetSkeleton( const std::string & key )
{
TMap::iterator it = mMap.find(key);
if (it != mMap.end()) {
 
// return weak if alive
if (!it->second.second.expired())
return it->second.second;
 
// get rid of empty slot
else
mMap.erase(it);
}
return TWeak();
}
 
private:
typedef std::pair<TShared, TWeak> TPair;
typedef std::map<std::string, TPair> TMap;
TMap mMap;
};
 
AddSkeleton - клиент отвечает за создание объекта и уникальность ключа, обязан что-то делать если AddSkeleton вернул false (напр попробовать с др ключом/именем)

DeleteSkeleton - обнуляет shared, но используемый объект остается в мапе и доступен через GetSkeleton до тех пор пока все клиенты его не освободят

GetSkeleton - возвращает weak, клиент решает делать ли его shared (захватывать ли ресурс)

Кстати необязательно плодить менеджеров, достаточно одного на все типы, надо в качестве ключа взять пару typeid(T).name() + string. Ну это может и не очень хорошо т.к. напр SkeletonManager имеет ф-ционал специфичный для Skeleton
« Последнее редактирование: Август 21, 2016, 08:11 от Igors » Записан
ssoft
Программист
*****
Offline Offline

Сообщений: 579


Просмотр профиля
« Ответ #17 : Август 21, 2016, 16:59 »

Нет, не так shared и weak работают - они работают в связке. weak автоматически обнуляется, если ни одного shared больше нет.
Должно быть что-то типа этого (написал прямо здесь, возможны синтаксические ошибки)

Код
C++ (Qt)
struct SkeletonManager {
typedef std::shared_ptr<Skeleton> TShared;
typedef std::weak_ptr<Skeleton> TWeak;
 
bool AddSkeleton( const std::string & key, Skeleton * sk )
{
// check already in map and alive
TMap::iterator it = mMap.find(key);
if (it != mMap.end())
return false;
 
// create shared + weak
mMap[key] = TShared( sk );
return true;
}
 
bool DeleteSkeleton( const std::string & key )
{
TMap::iterator it = mMap.find(key);
if (it == mMap.end())
return false;
mMap.erase(it);
return true;
}
 
TWeak GetSkeleton( const std::string & key )
{
TMap::iterator it = mMap.find(key);
if (it != mMap.end())
return it.second;
return TWeak();
}
 
private:
typedef std::map<std::string, TSahred> TMap;
TMap mMap;
};
 
 

А еще лучше, чтобы избежать возможности явной работы с указателем на Skeleton.

Код
C++ (Qt)
template < _Skeleton >
bool AddSkeleton( const std::string & key )
{
// check already in map and alive
TMap::iterator it = mMap.find(key);
if (it != mMap.end())
return false;
 
// create shared + weak
mMap[key] = std::make_shared< _Skeleton >();
//mMap[key] = TShared( new _Skeleton );
return true;
}
 

Работа в программе будет выглядеть как

Код
C++ (Qt)
SkeletonManager manager;
...
SkeletonManager::TShared skeleton =  manager.GetSkeleton( key );
if ( skeleton )
{
   ...
}
 
 
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #18 : Август 22, 2016, 03:19 »

Нет, не так shared и weak работают - они работают в связке. weak автоматически обнуляется, если ни одного shared больше нет.
Не понял - Вы же сами (совершенно верно) рекомендовали возвращать weak, Я так и сделал - удаление обнуляет shared, но weak может еще жить

Должно быть что-то типа этого (написал прямо здесь, возможны синтаксические ошибки)
Без weak мы ничего не достигаем - мапа не хранит объекты которые могут существовать

А еще лучше, чтобы избежать возможности явной работы с указателем на Skeleton.
Код
C++ (Qt)
mMap[key] = std::make_shared< _Skeleton >();
//mMap[key] = TShared( new _Skeleton );
}
 
Не раз задумывался над подобным. С одной стороны да, хочется обеспечить чтобы все железно шло только через менеджера - иначе всегда остается вероятность ошибки/просмотра. Но на практике это часто неудобно. Тот же Skeleton - конструктор создаст его "пустым", потом его надо грузить (напр из файла), и необязательно он успешно загрузится. Потом апдейтить и.т.п. Тогда чего совать "неконсистентный" объект в глобальную мапу? А в multithreaded (пусть его здесь и нет) это уже прямая ошибка.
« Последнее редактирование: Август 22, 2016, 03:35 от Igors » Записан
ssoft
Программист
*****
Offline Offline

Сообщений: 579


Просмотр профиля
« Ответ #19 : Август 22, 2016, 15:09 »

Manager хранит shared, но возвращает то weak при вызове GetSkeleton. Сформированный weak и хранимый shared взаимосвязаны (взаимопреобразуемы) - как только shared будет удален (обнулен) все связанные с ним weak автоматически обнулятся. Так как shared и weak взаимопреобразуемы, то нет необходимости в одновременном хранении shared и weak.

В стандарте С++11 и выше можно использовать переменное количество аргументов шаблона для вызова произвольного конструктора Skeleton

Код:
	template < typename _Skeleton, typename ... _Arguments >
bool AddSkeleton( const std::string & key, _Arguments ... arguments )
{
// check already in map and alive
TMap::iterator it = mMap.find(key);
if (it != mMap.end())
return false;
 
// create shared + weak
mMap[key] = std::make_shared< _Skeleton >();
//mMap[key] = TShared( new _Skeleton( arguments ... ) );
return true;
}
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #20 : Август 22, 2016, 16:18 »

Manager хранит shared, но возвращает то weak при вызове GetSkeleton. Сформированный weak и хранимый shared взаимосвязаны (взаимопреобразуемы) - как только shared будет удален (обнулен) все связанные с ним weak автоматически обнулятся. Так как shared и weak взаимопреобразуемы, то нет необходимости в одновременном хранении shared и weak.
Есть. Пример

- клиент получает объект (GetSkeleton) и делает его shared,
- клиент удаляет объект из мапы (DeleteSkeleton), но это не ведет к уничтожению объекта
- клиент опять запрашивает GetSkeleton, в мапе его уже нет (в Вашем сценарии), получив NULL клиент вероятно создает новый объект, загружает его с диска и добавляет в менеджер

Итог: менеджер позволяет одновременное существование одинаковых объектов (или по крайней мере с 1 ключом)
Записан
ssoft
Программист
*****
Offline Offline

Сообщений: 579


Просмотр профиля
« Ответ #21 : Август 22, 2016, 21:13 »

Если клиент удаляет объект из мапы (DeleteSkeleton), то это ведет к моментальному или отложенному уничтожению объекта. Отложенное удаление возникает только в случае, если какой-либо клиент(ы) временно преобразовал weak указатель в shared для возможности использования. Как только все shared удаляются, уничтожается и объект (в традиционном случае). Наличие weak указателей на уничтожение объекта никак не влияет.

Фактически возможно кратковременное существование двух и даже более подобных объектов - это плата за отсутствие синхронизации. Без явной синхронизации достигается так называемая "согласованность в конечном счете". Если требуется строгое наличие только одного экземпляра, то необходимо применять методы явной синхронизации уже с их недостатками (блокировать работу с менеджером до полного удаления скелетона).

В любом случае необходимо защитить мапу от одновременного доступа Mutex или ReadWriteLocker.

Могу отметить, что оба подхода в экстремальной ситуации (перегрузка процессора) ведут себя по разному плохо. Однако согласованность в конечном счете лучше параллелизуется. Но если есть другие ограничения, например по оперативной или графической памяти, то второй вариант может быть и лучше. Здесь все зависит от конкретных условий функционирования ПО.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #22 : Август 23, 2016, 09:31 »

Фактически возможно кратковременное существование двух и даже более подобных объектов - это плата за отсутствие синхронизации.
В данном случае этой платы можно легко избежать. К тому же будет ли это существование кратко (или долго) временным - решает клиент.

В любом случае необходимо защитить мапу от одновременного доступа Mutex или ReadWriteLocker.
Наверное атомарный мутекс здесь бы лучше подошел. Multi-threaded нет и в обозримом будущем не предвидится. Есть десятка 2 "контроллеров", некоторые из них сложные, но многим нужны те же скелетоны и др ресурсы. Использование менеджеров мне кажется вполне оправданным 
Записан
Страниц: 1 [2]   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.13 секунд. Запросов: 19.