Можно пускать пожар\волну "заразы" - по сигналам метить объекты флагом ToDie, а как signals станет нулем, слать бродкаст "умрите уже".
Это хуже предложенных мной двух волн (инвалидате и умрите) в случаях когда должна умереть незначительная часть всей сцены. Фактически Вы лишь заменили вторую волну на броадкаст сигнал. Да, это можно засчитать за третий способ (как модификацию первого), это лишь я сознательно отказываюсь пока возможно от броадкаст сигналов, даже предпочитая заменять их на посылку сигналов самому себе (здесь можно так же заменить).
Ещё как вариант можно действительно вместо рассылки броадкаст сигналов просто накапливать список объектов в списке и только им и слать сигнал "да умрите уже". Но многопоточная (параллельная) работа с этим списком ... дело такое, не быстрое. Хотя может и быстрее рассылки сигналов.
То есть "обрастаем" проверками: уже умершим не посылаем, пока не выгребем всю свою очередь сообщений - не умираем...
Ещё и проверять обнуление signals, иначе можем умереть раньше чем волна дойдёт до какого-то родителя и он уже соберётся послать нам сигнал, но тот ещё не попал к нам в очередь (вполне возможная ситуация при многопоточном выполнении). А у меня в коде сначала увеличивается signals, а уже потом реально рассылаются сигналы, и в промежутке от увеличения signals до попадания сигнала в очередь потомок может умереть по сигналу другого родителя. Короче гонки тут, и как их аккуратно исключить надо додумывать.
george66Ещё возможный вариант, уже со списком родителей в каждом объекте: при получении от любого родителя сигнала умри оповещаем всех родителей (подсчитывая их количество) что собираемся умереть, при получении подтверждения от всех из них о приёме уведомления (и исключении из своего списка потомков) умираем. Это разумеется кроме оповещения всех потомков. И тоже возможны гонки: даже если исключать из опроса родителя от которого пришёл сигнал умри, всё равно возможна ситуация когда мы шлём потомку сигнал умри, а он в этот момент шлёт нам уведомления "собираюсь умереть" (о чём мы ещё не знаем), мы же получили сигналы от всех своих родителей и умираем. Не уверен что ожидание опустошения своей очереди сигналов будет достаточно для исключения гонок. Да и вообще мне такое усложнение ещё менее нравится.
george66Вы бы это, сказали наконец предполагается ли многопоточное выполнение или обработка сообщений всей сцены строго в один поток? Это принципиально. В один поток можно исключить много проверок и тонкостей с взаимным расположением операций. Но тогда при попытке запустить многопоточно оно практически гарантированно обрушится.
Второй вопрос, лично меня волнующий: система должна быть распределённой (в смысле иметь доступ только к своему объекту и возможно глобальным переменным, а всё прочее только сигналами) или допускается обращение к любой переменной любого объекта всей сцены? Во втором случае лучшим может оказаться решение
rockclimber с добавлением объектов в список, который потом вычерпывается от готовых к операции объектов, может даже и выполняемое многопоточно.
Или задача учебная и Вам важны все возможные варианты?
-- 18.08.2020, 13:50 --george66Кстати, в распределённой системе собственно не может быть глобальных переменных, только локальные и среда обмена сигналами, тогда пул глобальных переменных засовываем в отдельный объект со своей очередью сообщений/сигналов и для любой модификации "глобальной переменной" шлём сигнал этому объекту о необходимом изменении нужной переменной. А он уже занимается подсчётами и уведомляет систему об окончании волн (и начальный объект об завершении волны invalidate). В такой ситуации можно поставить вопрос оптимизации обмена сигналами (исключении глобальных переменных или минимизации операций с ними).
Плюс обычно в сигналах/сообщениях предусматривается поле для параметра (обычно одного, если надо больше то передаётся ссылка на структуру, создать и переслать которую в память принимающего объекта отдельная задача), тогда вполне можно передавать значения глобальных счётчиков прямо в самом сигнале и отказаться от глобальных переменных. А указатель на начальный объект или добавить в структуру сигнала, или послать сигналом специальному объекту, вся роль которого будет лишь в запоминании начального объекта и перенаправлении ему сигнала done от любого объекта когда завершится волна invalidate.
В принципе, заведение отдельных объектов на каждое глобальное свойство и действие вполне обычная практика, ведь это дешёво в realtime, неисполняющиеся объекты ресурсов процессора не занимают, а памяти всегда достаточно (на штучное количество служебных объектов в дополнение к тысячам [десяткам/сотням тысяч] обычных).
Вообще, проектирование распределённых систем (в смысле доступности лишь локальных свойств, всё же прочее только через обмен сигналами) интересное занятие, любой шаг в сторону (смена порядка операций, добавление или убавление сигналов, добавление глобальных свойств/статистики, да много всего) часто рушит всю систему: или сигналы перестают распространяться, или часть сцены попадает в взаимную блокировку, или сеть заспамивается сигналами. Зато как в клеточных автоматах, одинаковый простой алгоритм в каждом объекте приводит к сложному поведению всей сцены, красота.