|
|
|
Альтернативный вариант задания функции процесса |
|
|
|
Nov 10 2012, 13:36
|
Частый гость
Группа: Участник
Сообщений: 142
Регистрация: 10-11-12
Пользователь №: 74 318
|
Приветствую. Начал смотреть 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) Более привычный способ реализации ф-ции. Кто что думает на этот счёт?
--------------------
|
|
|
|
|
Nov 10 2012, 16:10
|
Частый гость
Группа: Участник
Сообщений: 142
Регистрация: 10-11-12
Пользователь №: 74 318
|
AHTOXA, по идее вообще никак не должно влиять на быстродействие и потребление памяти, т.к. реально дополнительный исполняемый код вообще не добавляется по сравнению с оригинальной версией. Это просто другой способ определить функцию процесса. Выкладываю доработанные файлы в архиве.
Прикрепленные файлы
Common.zip ( 6.92 килобайт )
Кол-во скачиваний: 39
--------------------
|
|
|
|
|
Nov 10 2012, 16:31
|
фанат дивана
Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684
|
Ну что я могу сказать... Мне очень понравилось. Это именно то, о чём так долго говорили большевики мы с ReAl'ом Проблема только в потере совместимости со всеми существующими проектами. Будет интересно услышать, что скажут остальные участники.
--------------------
Если бы я знал, что такое электричество...
|
|
|
|
|
Nov 11 2012, 03:21
|
Adept
Группа: Свой
Сообщений: 3 469
Регистрация: 6-12-04
Из: Novosibirsk
Пользователь №: 1 343
|
QUOTE (ArtDenis @ Nov 10 2012, 20:36) Необходимость реализовывать функцию процесса внутри поля имён OS, Откуда взяли, что это необходимость? Не помню, чтобы у меня где-то прикладные процессы жили в пространстве имён OS. QUOTE (ArtDenis @ Nov 10 2012, 20:36) а добавление template <> вызывает некоторое удивление Откуда удивление? Это стандартное требование языка С++ - если не указана общая (generic) реализация, будьте добры предоставить специализацию, которую необходимо обозначить в соответсвии с требованиями языка. Функция exeс и является полной специализацией. QUOTE (ArtDenis @ Nov 10 2012, 20:36) Подумалось, почему-бы не сделать ф-цию exec просто ф-цией своего собственного класса? На скорую руку сделал несколько изменений в исходниках scmRTOS и весь код декларации и реализации процесса превратился в: Т.е. в итоге вместо одного template<> нужно создавать каждый раз целый класс. Сомнительне преимущество. Что касается инкапсуляции, то этот принцип можно реализовать и на текущем варианте, только использовав отношение включения вместо отношения наследования, как это сделано у вас. QUOTE (AHTOXA @ Nov 10 2012, 22:59) Во! Я всегда мечтал, чтоб можно было того, инкапсулировать Уже обсуждали мы это. Что мешает тебе инкапсулировать, написав обёртку вокруг процесса? В данном случае я вижу появление лишней сущности. Их и так там две - TBaseProcess и process<>, но это сделано из соображений эффективности реализации. А третья добавляется только из синтаксических предпочтений.
--------------------
«Отыщи всему начало, и ты многое поймёшь» К. Прутков
|
|
|
|
|
Nov 11 2012, 05:00
|
Частый гость
Группа: Участник
Сообщений: 142
Регистрация: 10-11-12
Пользователь №: 74 318
|
Цитата(dxp @ Nov 11 2012, 09:21) Откуда взяли, что это необходимость? Не помню, чтобы у меня где-то прикладные процессы жили в пространстве имён OS. А как тогда можно сделать без реализации функции процесса внутри namespace OS ? Я просто пока что судил по примерам, которые идут с scmRTOS. Цитата(dxp @ Nov 11 2012, 09:21) Откуда удивление? Это стандартное требование языка С++ - если не указана общая (generic) реализация, будьте добры предоставить специализацию, которую необходимо обозначить в соответсвии с требованиями языка. Функция exeс и является полной специализацией. Я могу ошибаться, но считается, что уровень познаний в языке программиста который использует библиотеку, обычно меньше, чем уровень знаний того, кто эту библиотеку пишет. Поэтому библиотека может быть сложной внутри, но её использование должно быть простым и понятным. Лично я видел очень небольшое количество С++ библиотек, которые бы заставляли программиста писать специализацию вот таким вот образом, да и то это приходилось делать в очень исключительных случаях. Поэтому и вызывает удивление, что практически базовая функциональность реализована через требование специализации шаблонной функции, которая вызывается библиотекой. Цитата(dxp @ Nov 11 2012, 09:21) Т.е. в итоге вместо одного template<> нужно создавать каждый раз целый класс. Сомнительне преимущество. Да, именно класс. И в этом преимущество, т.к. класс в с++ - это более универсальная вещь, чем функция. Цитата(dxp @ Nov 11 2012, 09:21) Что касается инкапсуляции, то этот принцип можно реализовать и на текущем варианте, только использовав отношение включения вместо отношения наследования, как это сделано у вас. Можно пример? Просто я не представляю как это можно сделать без лишних телодвижений.
--------------------
|
|
|
|
|
Nov 11 2012, 06:07
|
фанат дивана
Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684
|
Цитата(dxp @ Nov 11 2012, 09:21) Уже обсуждали мы это. Что мешает тебе инкапсулировать, написав обёртку вокруг процесса? В данном случае я вижу появление лишней сущности. Их и так там две - TBaseProcess и process<>, но это сделано из соображений эффективности реализации. А третья добавляется только из синтаксических предпочтений. Да, обсуждали. В тот раз я не смог тебя убедить Но тогда раз предложенное мной решение было связано с дополнительными расходами. А это решение - не влечёт никаких доп. расходов. Зачем писать обёртку, если можно инкапсулировать всё прямо в классе процесса? Вот как раз-таки обёртка - это лишняя сушность. Существующий подход позволяет пользователю специализировать только функцию exec(). А предложенный - позволяет полноценно наследовать класс процесса. Какой вариант гибче?
--------------------
Если бы я знал, что такое электричество...
|
|
|
|
|
Nov 11 2012, 12:02
|
Adept
Группа: Свой
Сообщений: 3 469
Регистрация: 6-12-04
Из: Novosibirsk
Пользователь №: 1 343
|
QUOTE (ArtDenis @ Nov 11 2012, 12:00) А как тогда можно сделать без реализации функции процесса внутри namespace OS ? Я просто пока что судил по примерам, которые идут с scmRTOS. Я не знаю, какие примеры вы смотрели, в моих примерах этого нет и никогда не было, мне даже в голову не приходило помещать функцию процесса в пространство имён OS - ведь функция процесса - это уже прикладной код, а не код ОС. Исключение составляет фоновый процесс Idle, он целиком помещён в пространство имён OS. QUOTE (ArtDenis @ Nov 11 2012, 12:00) Я могу ошибаться, но считается, что уровень познаний в языке программиста который использует библиотеку, обычно меньше, чем уровень знаний того, кто эту библиотеку пишет. Поэтому библиотека может быть сложной внутри, но её использование должно быть простым и понятным. Лично я видел очень небольшое количество С++ библиотек, которые бы заставляли программиста писать специализацию вот таким вот образом, да и то это приходилось делать в очень исключительных случаях. Поэтому и вызывает удивление, что практически базовая функциональность реализована через требование специализации шаблонной функции, которая вызывается библиотекой. Всё правильно, так и есть. И насколько мне известно, scmRTOS использует много людей, которые в плюсах не особенно подготовлены (а немало из них не особенно и стремится постичь глубины С++), им вполне достаточно знать базовый синтаксис использования, основное из которого - это обращение <ObjectName.MemberName>. И уж написать один раз перед функций template<> никакого труда не составляет, при этом совершенно нет необходимости напрягаться по поводу специализаций и прочего. Вы же предлагаете вариант с созданием класса да ещё и не самым тривиальным способом (наследование от шаблона по методу стратегии), тут у пользователя, который писал, пишет и собирается продолжать писать в С-стиле, вопросов возникнет куда больше - ему придётся врубаться в синтаксис определения классов и наследования, создавать свои определения классов и т.д. - словом, писать свой код в С++ стиле по полной программе. Это совсем не то же самое, что просто создать определение функции по образцу и использовать её в привычном С-стиле. Вас смущает слово template<>? А слово OS_PROCESS, которое используются там же, вас не смущает? QUOTE (ArtDenis @ Nov 11 2012, 12:00) Да, именно класс. И в этом преимущество, т.к. класс в с++ - это более универсальная вещь, чем функция. А если в ряде случаев эта универсальность не нужна? Тогда накладяки на пустом месте. Процесс должен предоставлять отдельный асинхронный поток управления, он это делает - предоставляет функцию exec. Больше он ничего не должен. Зачем его нагружать в базовом исполнении, мотивируя гипотетическими фичами? Лишнее это. База есть. Если кому мало - вэлком, можно расширять. QUOTE (ArtDenis @ Nov 11 2012, 12:00) Можно пример? Просто я не представляю как это можно сделать без лишних телодвижений. Очень просто. Если вам или кому-либо ещё хочется иметь функциональность процесса инакпсулиированной в объекте, определите этот объект, сделайте его "процессную" функцию встраиваемой (чтобы вызова не было) и вызывайте её из process<>::exec(). Всё. Существующий подход предоставляет бОльшую гикость и простоту. Можно сделать так, а можно эдак. Далее, по проектированию. Хороший стиль проектирования подразумевает: "одна сущность - один класс". Один процесс очень часто участвует в реализации далеко не одной сущности, поэтому запихивание всех реализаций в один класс процесса выглядит просто данью парадигме программирования. Вышеописанный способ (определение класса и вызов его "процессной" функии из функции процесса) свободен от этого недостатка - можно создать несколько классов этим способом и вызывать их функции из exec. Инкапсуляция на месте, искусственных "привязок" "класс-процесс" нет. QUOTE (AHTOXA @ Nov 11 2012, 13:07) Да, обсуждали. В тот раз я не смог тебя убедить Приводимыми агрументами и не удастся. Контрагументы, имхо, сильнее. QUOTE (AHTOXA @ Nov 11 2012, 13:07) Зачем писать обёртку, если можно инкапсулировать всё прямо в классе процесса? Вот как раз-таки обёртка - это лишняя сушность. Не более лишняя, чем определение класса в предлагаемом варианте. Скажи, чем отношение наследования лучше отношения включения? В данном конкретном случае. Чем хуже, уже говорилось: в текущем варианте можно юзать функцию процесса, как есть, в С-стиле, можно включить в другой класса, причём двумя способами - отнаследовашись от process<> или вызывая из process<>::exec() функции других классов, которые реализуют принципы инкапсуляции и абстракции, в то время, как предлагаемый вариант предоставляет только один способ - безальтернативно включить весь код процесса в один класс. QUOTE (AHTOXA @ Nov 11 2012, 13:07) Существующий подход позволяет пользователю специализировать только функцию exec(). А предложенный - позволяет полноценно наследовать класс процесса. Какой вариант гибче? Что мешает тебе наследовать от process<>? Хотя я бы так не делал - лучше написать отдельный класс и вызывать его функцию (или функции) из exec.
--------------------
«Отыщи всему начало, и ты многое поймёшь» К. Прутков
|
|
|
|
|
Nov 11 2012, 12:43
|
Частый гость
Группа: Участник
Сообщений: 142
Регистрация: 10-11-12
Пользователь №: 74 318
|
Цитата(dxp @ Nov 11 2012, 18:02) Я не знаю, какие примеры вы смотрели, в моих примерах этого нет и никогда не было, мне даже в голову не приходило помещать функцию процесса в пространство имён OS - ведь функция процесса - это уже прикладной код, а не код ОС Я смотрел примеры AVR и Cortex3 для GCC. Там везде ф-ция процесса реализована в namespace OS.
Сообщение отредактировал ArtDenis - Nov 11 2012, 12:43
--------------------
|
|
|
|
|
Nov 11 2012, 16:00
|
фанат дивана
Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684
|
Цитата(dxp @ Nov 11 2012, 19:00) Помещать функцию в пространство имён или не помещать - это личное предпочтение автора примера, ни язык, ни ОС этого не требуют. В других примерах - тот же AVR/IAR, в частности, этого нет. Вообще-то она изначально туда помещена, в объявлении. То, что некоторые компиляторы до сих пор позволяют не указывать это в реализации, не выносит exec() из пространства имён OS. Цитата(dxp @ Nov 11 2012, 18:02) Приводимыми агрументами и не удастся. Контрагументы, имхо, сильнее. Или же кто-то просто упёрся Цитата(dxp @ Nov 11 2012, 18:02) Не более лишняя, чем определение класса в предлагаемом варианте. Скажи, чем отношение наследования лучше отношения включения? В данном конкретном случае. А где ты видишь здесь включение? Никакого включения нет. Есть вызов некой функции некоего стороннего объекта из функции exec() другого класса. Какое же это включение? Цитата(dxp @ Nov 11 2012, 18:02) предлагаемый вариант предоставляет только один способ - безальтернативно включить весь код процесса в один класс. Опять не так. Что мешает включить какой-то другой объект в класс процесса? Или же, по-нынешнему, вызвать из exec() функции любого другого объекта? Короче, сплошные профиты от нынешнего варианта. А недостатков я по-прежнему не вижу Цитата(dxp @ Nov 11 2012, 18:02) Что мешает тебе наследовать от process<>? Хотя я бы так не делал - лучше написать отдельный класс и вызывать его функцию (или функции) из exec. Не помню, но что-то вроде мешает. Не получается, емнимс. Хотя надо попробовать...
--------------------
Если бы я знал, что такое электричество...
|
|
|
|
|
Nov 11 2012, 19:15
|
фанат дивана
Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684
|
Йоу! Я придумал, как совместить эти два варианта Короче, переименовываем в новом варианте 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) - тоже. Получается вообще замечательно: старые проекты все подхватятся без изменений, а в новых пользователь имеет возможность выбрать для себя более удобный вариант.
--------------------
Если бы я знал, что такое электричество...
|
|
|
|
|
Nov 11 2012, 20:07
|
Нечётный пользователь.
Группа: Свой
Сообщений: 2 033
Регистрация: 26-05-05
Из: Бровари, Україна
Пользователь №: 5 417
|
Цитата(ArtDenis @ Nov 11 2012, 07:00) Лично я видел очень небольшое количество С++ библиотек, которые бы заставляли программиста писать специализацию вот таким вот образом, да и то это приходилось делать в очень исключительных случаях. Старые версии компиляторов могли пропускать, но если нужно сделать свою специализацию шаблона, то иначе по стандарту нельзя. Цитата(AHTOXA @ Nov 10 2012, 18:31) Ну что я могу сказать... Мне очень понравилось. Это именно то, о чём так долго говорили большевики мы с ReAl'ом Да-да-да. Цитата(AHTOXA @ Nov 10 2012, 18:31) Проблема только в потере совместимости со всеми существующими проектами. Будет интересно услышать, что скажут остальные участники. Вот потому и я вчера промолчал. Кроме «наконец свершилось» всё равно ничего в голову не лезло :-) Цитата(AHTOXA @ Nov 11 2012, 18:00) Вообще-то она изначально туда помещена, в объявлении. То, что некоторые компиляторы до сих пор позволяют не указывать это в реализации, не выносит exec() из пространства имён OS. Собственно, оно и в примерах появилось в ответ на ругань более свежих версий компиляторов. Цитата(AHTOXA @ Nov 11 2012, 21:15) Йоу! Я придумал, как совместить эти два варианта Да, похоже, так лучше. Я уж начал было думать про просто параллельное существование нынешнего process и нового. Но это плохо, по сути одно и то же и при модификациях требовало бы менять в двух местах. Цитата(AHTOXA @ Nov 11 2012, 18:00) Не помню, но что-то вроде мешает. Не получается, емнимс. Exec() в этом унаследованном от шаблона получается другой (перегруженный). А шаблон хочет затолкать куда надо адрес своего, который остается неопределённым.
--------------------
Ну, я пошёл… Если что – звоните…
|
|
|
|
|
Nov 12 2012, 02:41
|
Частый гость
Группа: Участник
Сообщений: 142
Регистрация: 10-11-12
Пользователь №: 74 318
|
Цитата(AHTOXA @ Nov 12 2012, 01:15) Йоу! Я придумал, как совместить эти два варианта Да, удачное решение Мне оно в голову не пришло
--------------------
|
|
|
|
|
Nov 12 2012, 07:13
|
Гуру
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095
|
QUOTE (AHTOXA @ Nov 11 2012, 21:15) Я придумал, как совместить эти два варианта Выглядит слабочитаемо. Что мешает завести свой потомок TBaseProcess вне пространства имен OS, оставив в покое родной шаблон? QUOTE (ArtDenis @ Nov 10 2012, 15:36) CODE class TProc1 : public OS::process<TProc1, OS::pr0, 300> Тут TProc1 передается как параметр шаблона только для того, чтобы в конструкторе взять адрес его exec. Страдает мое чувство прекрасного. Возможно менее разрушительным будет добавить второй конструктор, который получает адрес exec в качестве параметра? Или сделать этот конструктор с параметром единственным, задав ему значение по умолчанию? А в потомке вызывать с адресом своего exec. Тоже некрасиво - забудешь в потомке описать такой конструктор и компилятор не отловит. Не знаю. Хотя отловит - линкер выругается, что не определен exec() в предке... Но такое сообщение неверно описывает причину ошибки. Как вариант - можно добавить обсуждаемую фичу в Extensions. Именно как отдельного наследника TBaseProcess.
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|