ВходНаше всё Теги codebook 无线电组件 Поиск Опросы Закон Суббота
13 июля
490204
fk0, легенда (21.02.2014 16:44, просмотров: 2022)
Предположим, в терминах C++, что есть ряд глобальных объектов. Которые к тому же взаимодействуют между собой без определённого порядка (нет чёткой иерархии, нельзя часть из них сделать вложенными в другие). Чтобы вся система работала нужно чтоб не было ситуации использования объекта до вызова его конструктора. Если бы можно было исключить вызов в конструкторе методов других объектов (классов), то нет проблем. Но де-факто это сделать сложно и всё равно потребуется механизм о котором речь пойдёт ниже. Нужен, стало быть, определённый порядок вызова конструкторов. Например, GCC предлагает такой вариант такой вариант. Неудобство в том, что нужно вручную назначать эти цифры приоритета и где-то на бумажке записать шпаргалку, чтоб не ошибиться. Аналогичная проблема существует в init-скриптах unix-подобных систем. Там тоже запуск части сервисов (демонов, служб) привязан к другим которые должны быть запущены раньше. в SysV init это решается так же -- цифрами. Есть и более простой механизм а-ля BSD 3-й версии -- просто вручную вызвать что нужно из вручную написанного /etc/rc.init (вручную вызвать нужные функции из main()...) Этот простой механизм применительно к программированию на C/C++ неудобен необходимостью ручной поддержки этого списка, и в частности, нельзя из одного набора исходников получать разные бинарники просто путём включения/исключения ненужных *.o файлов -- что совсем уж неудобно. Речь вообще не о C++, а о plain C, но сущности это не меняет, просто так трудней с терминологией. Такой механизм, подобный init_priority в GCC или SysV init и сделан. Но он этими цифрами и неудобен. Хотелось бы автоматического разрешения зависимостей, кто от кого зависит, и соответственно определённого порядка запуска. Как бы эту задачу разрешить в рамках C-компилятора? В рамках C++ разрешается через конструкторы, вызываемые до main, в рамках C похожим образом через ручной их вызов из main по списку с приоритетами, формируемому в момент компиляции -- адреса "конструкторов" кладутся в специальную секцию линкером. Но хотелось бы избавиться от ручного назначения цифр. Понятно, что компилятор сам не вызовет в нужном порядке. Максимум можно получить какой-то массив, в котором есть указатели на фунции и как-то описаны их зависимости и далее отдельная функция должна решить какой должен быть порядок и в этом порядке вызвать (уже в рантайме). Вначале вызываем конструкторы ни от чего не зависимых объектов, потом зависимости от этих объектов считаем разрешёнными и так в рекурсии. И запоминаем какие уже (делаем singleton) вызваны. Кажется медленным, наверное можно пойти с другого конца -- брать первый попавшийся класс и спускаться по дереву его зависимостей до конца. Как описывать зависимости? Описателем зависимостей может являться ссылка на список указателей конструкторов классов от которых зависит каждый конкретный класс. Т.е. в специальную секцию помещаются не список указателей на конструкторы с их приоритетом (как сейчас): static const struct { int (*init_func)(void); unsigned priority; } anonymous#__LINE__ __attribute__((section("myinit"))); А что-то вроде: struct _s_constructor { int (*init_func)(void); const struct _s_constructor *depend[]; }; const /* NOT STATIC! */ struct _s_constructor classname __attribute__((section("myinit"))) = { .init_func = module_name_init, .depend = { otherclass1, otherclass2, NULL } }; Можно даже static объекты делать, не видимые за пределами модуля, с именем anonymous#__LINE__, но от них ничего зависеть не должно, они должны быть только зависимые. Может как-то по другому можно?
[ZX]