ArtDenis 0 November 10, 2012 Posted November 10, 2012 · Report post Приветствую. Начал смотреть scmRTOS. Сразу начал резать глаз способ реализации функции процесса: typedef OS::process<OS::pr0, 300> TProc1; namespace OS { template <> OS_PROCESS void TProc1::exec() { for(;;) { ef.wait(); PB0.Off(); } } } Необходимость реализовывать функцию процесса внутри поля имён OS, а добавление template <> вызывает некоторое удивление Подумалось, почему-бы не сделать ф-цию exec просто ф-цией своего собственного класса? На скорую руку сделал несколько изменений в исходниках scmRTOS и весь код декларации и реализации процесса превратился в: class TProc1 : public OS::process<TProc1, OS::pr0, 300> { public: static void exec() { for(;;) { ef.wait(); PB0.Off(); } } }; Что мы в итоге имеем? 1) Класс, в котором можно инкапсулировать данные и методы процесса. Закрытые и используемые только в TProc1 данные можно объявить в секции private класса и никто к ним не получит доступ. 2) Более привычный способ реализации ф-ции. Кто что думает на этот счёт? Quote Share this post Link to post Share on other sites More sharing options...
AHTOXA 25 November 10, 2012 Posted November 10, 2012 · Report post Что мы в итоге имеем? 1) Класс, в котором можно инкапсулировать данные и методы процесса. Закрытые и используемые только в TProc1 данные можно объявить в секции private класса и никто к ним не получит доступ. 2) Более привычный способ реализации ф-ции. Кто что думает на этот счёт? Во! Я всегда мечтал, чтоб можно было того, инкапсулировать:) Вопрос только такой: какие изменения были внесены в саму ось, и как это отразилось на размере кода/быстродействии/размере ОЗУ? Quote Share this post Link to post Share on other sites More sharing options...
ArtDenis 0 November 10, 2012 Posted November 10, 2012 · Report post AHTOXA, по идее вообще никак не должно влиять на быстродействие и потребление памяти, т.к. реально дополнительный исполняемый код вообще не добавляется по сравнению с оригинальной версией. Это просто другой способ определить функцию процесса. Выкладываю доработанные файлы в архиве. Common.zip Quote Share this post Link to post Share on other sites More sharing options...
AHTOXA 25 November 10, 2012 Posted November 10, 2012 · Report post Ну что я могу сказать... Мне очень понравилось. Это именно то, о чём так долго говорили большевики мы с ReAl'ом :) Проблема только в потере совместимости со всеми существующими проектами. Будет интересно услышать, что скажут остальные участники. Quote Share this post Link to post Share on other sites More sharing options...
dxp 228 November 11, 2012 Posted November 11, 2012 · Report post Необходимость реализовывать функцию процесса внутри поля имён OS, Откуда взяли, что это необходимость? Не помню, чтобы у меня где-то прикладные процессы жили в пространстве имён OS. а добавление template <> вызывает некоторое удивление Откуда удивление? Это стандартное требование языка С++ - если не указана общая (generic) реализация, будьте добры предоставить специализацию, которую необходимо обозначить в соответсвии с требованиями языка. Функция exeс и является полной специализацией. Подумалось, почему-бы не сделать ф-цию exec просто ф-цией своего собственного класса? На скорую руку сделал несколько изменений в исходниках scmRTOS и весь код декларации и реализации процесса превратился в: Т.е. в итоге вместо одного template<> нужно создавать каждый раз целый класс. Сомнительне преимущество. Что касается инкапсуляции, то этот принцип можно реализовать и на текущем варианте, только использовав отношение включения вместо отношения наследования, как это сделано у вас. Во! Я всегда мечтал, чтоб можно было того, инкапсулировать:) Уже обсуждали мы это. Что мешает тебе инкапсулировать, написав обёртку вокруг процесса? В данном случае я вижу появление лишней сущности. Их и так там две - TBaseProcess и process<>, но это сделано из соображений эффективности реализации. А третья добавляется только из синтаксических предпочтений. Quote Share this post Link to post Share on other sites More sharing options...
ArtDenis 0 November 11, 2012 Posted November 11, 2012 · Report post Откуда взяли, что это необходимость? Не помню, чтобы у меня где-то прикладные процессы жили в пространстве имён OS. А как тогда можно сделать без реализации функции процесса внутри namespace OS ? Я просто пока что судил по примерам, которые идут с scmRTOS. Откуда удивление? Это стандартное требование языка С++ - если не указана общая (generic) реализация, будьте добры предоставить специализацию, которую необходимо обозначить в соответсвии с требованиями языка. Функция exeс и является полной специализацией. Я могу ошибаться, но считается, что уровень познаний в языке программиста который использует библиотеку, обычно меньше, чем уровень знаний того, кто эту библиотеку пишет. Поэтому библиотека может быть сложной внутри, но её использование должно быть простым и понятным. Лично я видел очень небольшое количество С++ библиотек, которые бы заставляли программиста писать специализацию вот таким вот образом, да и то это приходилось делать в очень исключительных случаях. Поэтому и вызывает удивление, что практически базовая функциональность реализована через требование специализации шаблонной функции, которая вызывается библиотекой. Т.е. в итоге вместо одного template<> нужно создавать каждый раз целый класс. Сомнительне преимущество. Да, именно класс. И в этом преимущество, т.к. класс в с++ - это более универсальная вещь, чем функция. Что касается инкапсуляции, то этот принцип можно реализовать и на текущем варианте, только использовав отношение включения вместо отношения наследования, как это сделано у вас. Можно пример? Просто я не представляю как это можно сделать без лишних телодвижений. Quote Share this post Link to post Share on other sites More sharing options...
AHTOXA 25 November 11, 2012 Posted November 11, 2012 · Report post Уже обсуждали мы это. Что мешает тебе инкапсулировать, написав обёртку вокруг процесса? В данном случае я вижу появление лишней сущности. Их и так там две - TBaseProcess и process<>, но это сделано из соображений эффективности реализации. А третья добавляется только из синтаксических предпочтений. Да, обсуждали. В тот раз я не смог тебя убедить:) Но тогда раз предложенное мной решение было связано с дополнительными расходами. А это решение - не влечёт никаких доп. расходов. Зачем писать обёртку, если можно инкапсулировать всё прямо в классе процесса? Вот как раз-таки обёртка - это лишняя сушность. Существующий подход позволяет пользователю специализировать только функцию exec(). А предложенный - позволяет полноценно наследовать класс процесса. Какой вариант гибче? Quote Share this post Link to post Share on other sites More sharing options...
dxp 228 November 11, 2012 Posted November 11, 2012 · Report post А как тогда можно сделать без реализации функции процесса внутри namespace OS ? Я просто пока что судил по примерам, которые идут с scmRTOS. Я не знаю, какие примеры вы смотрели, в моих примерах этого нет и никогда не было, мне даже в голову не приходило помещать функцию процесса в пространство имён OS - ведь функция процесса - это уже прикладной код, а не код ОС. Исключение составляет фоновый процесс Idle, он целиком помещён в пространство имён OS. Я могу ошибаться, но считается, что уровень познаний в языке программиста который использует библиотеку, обычно меньше, чем уровень знаний того, кто эту библиотеку пишет. Поэтому библиотека может быть сложной внутри, но её использование должно быть простым и понятным. Лично я видел очень небольшое количество С++ библиотек, которые бы заставляли программиста писать специализацию вот таким вот образом, да и то это приходилось делать в очень исключительных случаях. Поэтому и вызывает удивление, что практически базовая функциональность реализована через требование специализации шаблонной функции, которая вызывается библиотекой. Всё правильно, так и есть. И насколько мне известно, scmRTOS использует много людей, которые в плюсах не особенно подготовлены (а немало из них не особенно и стремится постичь глубины С++), им вполне достаточно знать базовый синтаксис использования, основное из которого - это обращение <ObjectName.MemberName>. И уж написать один раз перед функций template<> никакого труда не составляет, при этом совершенно нет необходимости напрягаться по поводу специализаций и прочего. Вы же предлагаете вариант с созданием класса да ещё и не самым тривиальным способом (наследование от шаблона по методу стратегии), тут у пользователя, который писал, пишет и собирается продолжать писать в С-стиле, вопросов возникнет куда больше - ему придётся врубаться в синтаксис определения классов и наследования, создавать свои определения классов и т.д. - словом, писать свой код в С++ стиле по полной программе. Это совсем не то же самое, что просто создать определение функции по образцу и использовать её в привычном С-стиле. Вас смущает слово template<>? А слово OS_PROCESS, которое используются там же, вас не смущает? Да, именно класс. И в этом преимущество, т.к. класс в с++ - это более универсальная вещь, чем функция. А если в ряде случаев эта универсальность не нужна? Тогда накладяки на пустом месте. Процесс должен предоставлять отдельный асинхронный поток управления, он это делает - предоставляет функцию exec. Больше он ничего не должен. Зачем его нагружать в базовом исполнении, мотивируя гипотетическими фичами? Лишнее это. База есть. Если кому мало - вэлком, можно расширять. Можно пример? Просто я не представляю как это можно сделать без лишних телодвижений. Очень просто. Если вам или кому-либо ещё хочется иметь функциональность процесса инакпсулиированной в объекте, определите этот объект, сделайте его "процессную" функцию встраиваемой (чтобы вызова не было) и вызывайте её из process<>::exec(). Всё. Существующий подход предоставляет бОльшую гикость и простоту. Можно сделать так, а можно эдак. Далее, по проектированию. Хороший стиль проектирования подразумевает: "одна сущность - один класс". Один процесс очень часто участвует в реализации далеко не одной сущности, поэтому запихивание всех реализаций в один класс процесса выглядит просто данью парадигме программирования. Вышеописанный способ (определение класса и вызов его "процессной" функии из функции процесса) свободен от этого недостатка - можно создать несколько классов этим способом и вызывать их функции из exec. Инкапсуляция на месте, искусственных "привязок" "класс-процесс" нет. Да, обсуждали. В тот раз я не смог тебя убедить:) Приводимыми агрументами и не удастся. :) Контрагументы, имхо, сильнее. Зачем писать обёртку, если можно инкапсулировать всё прямо в классе процесса? Вот как раз-таки обёртка - это лишняя сушность. Не более лишняя, чем определение класса в предлагаемом варианте. Скажи, чем отношение наследования лучше отношения включения? В данном конкретном случае. Чем хуже, уже говорилось: в текущем варианте можно юзать функцию процесса, как есть, в С-стиле, можно включить в другой класса, причём двумя способами - отнаследовашись от process<> или вызывая из process<>::exec() функции других классов, которые реализуют принципы инкапсуляции и абстракции, в то время, как предлагаемый вариант предоставляет только один способ - безальтернативно включить весь код процесса в один класс. Существующий подход позволяет пользователю специализировать только функцию exec(). А предложенный - позволяет полноценно наследовать класс процесса. Какой вариант гибче? Что мешает тебе наследовать от process<>? Хотя я бы так не делал - лучше написать отдельный класс и вызывать его функцию (или функции) из exec. Quote Share this post Link to post Share on other sites More sharing options...
ArtDenis 0 November 11, 2012 Posted November 11, 2012 (edited) · Report post Я не знаю, какие примеры вы смотрели, в моих примерах этого нет и никогда не было, мне даже в голову не приходило помещать функцию процесса в пространство имён OS - ведь функция процесса - это уже прикладной код, а не код ОС Я смотрел примеры AVR и Cortex3 для GCC. Там везде ф-ция процесса реализована в namespace OS. Edited November 11, 2012 by ArtDenis Quote Share this post Link to post Share on other sites More sharing options...
dxp 228 November 11, 2012 Posted November 11, 2012 · Report post Я смотрел примеры AVR и Cortex3 для GCC. Там везде ф-ция процесса реализована в namespace OS. Помещать функцию в пространство имён или не помещать - это личное предпочтение автора примера, ни язык, ни ОС этого не требуют. В других примерах - тот же AVR/IAR, в частности, этого нет. Quote Share this post Link to post Share on other sites More sharing options...
AHTOXA 25 November 11, 2012 Posted November 11, 2012 · Report post Помещать функцию в пространство имён или не помещать - это личное предпочтение автора примера, ни язык, ни ОС этого не требуют. В других примерах - тот же AVR/IAR, в частности, этого нет. Вообще-то она изначально туда помещена, в объявлении. То, что некоторые компиляторы до сих пор позволяют не указывать это в реализации, не выносит exec() из пространства имён OS. Приводимыми агрументами и не удастся. :) Контрагументы, имхо, сильнее. Или же кто-то просто упёрся:) Не более лишняя, чем определение класса в предлагаемом варианте. Скажи, чем отношение наследования лучше отношения включения? В данном конкретном случае. А где ты видишь здесь включение? Никакого включения нет. Есть вызов некой функции некоего стороннего объекта из функции exec() другого класса. Какое же это включение? предлагаемый вариант предоставляет только один способ - безальтернативно включить весь код процесса в один класс. Опять не так. Что мешает включить какой-то другой объект в класс процесса? Или же, по-нынешнему, вызвать из exec() функции любого другого объекта? Короче, сплошные профиты от нынешнего варианта. А недостатков я по-прежнему не вижу:) Что мешает тебе наследовать от process<>? Хотя я бы так не делал - лучше написать отдельный класс и вызывать его функцию (или функции) из exec. Не помню, но что-то вроде мешает. Не получается, емнимс. Хотя надо попробовать... Quote Share this post Link to post Share on other sites More sharing options...
AHTOXA 25 November 11, 2012 Posted November 11, 2012 · Report post Йоу! Я придумал, как совместить эти два варианта :08: Короче, переименовываем в новом варианте process в customProcess, а process объявляем вот так: template<TPriority pr, size_t stack_size> class process : public customProcess<process<pr, stack_size>, pr, stack_size> { public: OS_PROCESS static void exec(); }; И всё! Старый вариант работает, и новый (наследование от customProcess) - тоже. Получается вообще замечательно: старые проекты все подхватятся без изменений, а в новых пользователь имеет возможность выбрать для себя более удобный вариант. :yeah: Quote Share this post Link to post Share on other sites More sharing options...
ReAl 0 November 11, 2012 Posted November 11, 2012 · Report post Лично я видел очень небольшое количество С++ библиотек, которые бы заставляли программиста писать специализацию вот таким вот образом, да и то это приходилось делать в очень исключительных случаях.Старые версии компиляторов могли пропускать, но если нужно сделать свою специализацию шаблона, то иначе по стандарту нельзя. Ну что я могу сказать... Мне очень понравилось. Это именно то, о чём так долго говорили большевики мы с ReAl'ом :)Да-да-да. Проблема только в потере совместимости со всеми существующими проектами. Будет интересно услышать, что скажут остальные участники. Вот потому и я вчера промолчал. Кроме «наконец свершилось» всё равно ничего в голову не лезло :-) Вообще-то она изначально туда помещена, в объявлении. То, что некоторые компиляторы до сих пор позволяют не указывать это в реализации, не выносит exec() из пространства имён OS.Собственно, оно и в примерах появилось в ответ на ругань более свежих версий компиляторов. Йоу! Я придумал, как совместить эти два варианта :08:Да, похоже, так лучше. Я уж начал было думать про просто параллельное существование нынешнего process и нового. Но это плохо, по сути одно и то же и при модификациях требовало бы менять в двух местах. Не помню, но что-то вроде мешает. Не получается, емнимс.Exec() в этом унаследованном от шаблона получается другой (перегруженный). А шаблон хочет затолкать куда надо адрес своего, который остается неопределённым. Quote Share this post Link to post Share on other sites More sharing options...
ArtDenis 0 November 12, 2012 Posted November 12, 2012 · Report post Йоу! Я придумал, как совместить эти два варианта :08: Да, удачное решение :) Мне оно в голову не пришло Quote Share this post Link to post Share on other sites More sharing options...
Сергей Борщ 198 November 12, 2012 Posted November 12, 2012 · Report post Я придумал, как совместить эти два вариантаВыглядит слабочитаемо. Что мешает завести свой потомок TBaseProcess вне пространства имен OS, оставив в покое родной шаблон? class TProc1 : public OS::process<TProc1, OS::pr0, 300> Тут TProc1 передается как параметр шаблона только для того, чтобы в конструкторе взять адрес его exec. Страдает мое чувство прекрасного. Возможно менее разрушительным будет добавить второй конструктор, который получает адрес exec в качестве параметра? Или сделать этот конструктор с параметром единственным, задав ему значение по умолчанию? А в потомке вызывать с адресом своего exec. Тоже некрасиво - забудешь в потомке описать такой конструктор и компилятор не отловит. Не знаю. Хотя отловит - линкер выругается, что не определен exec() в предке... Но такое сообщение неверно описывает причину ошибки. Как вариант - можно добавить обсуждаемую фичу в Extensions. Именно как отдельного наследника TBaseProcess. Quote Share this post Link to post Share on other sites More sharing options...