Перейти к содержанию
    

Альтернативный вариант задания функции процесса

Приветствую.

 

Начал смотреть scmRTOS. Сразу начал резать глаз способ реализации функции процесса:

typedef OS::process<OS::pr0, 300> TProc1;

namespace OS
{
    template <>
    OS_PROCESS void TProc1::exec()
    {
        for(;;)
        {
            ef.wait();
            PB0.Off();
        }
    }
}

Необходимость реализовывать функцию процесса внутри поля имён OS, а добавление template <> вызывает некоторое удивление :wacko:

 

Подумалось, почему-бы не сделать ф-цию exec просто ф-цией своего собственного класса? На скорую руку сделал несколько изменений в исходниках scmRTOS и весь код декларации и реализации процесса превратился в:

 

class TProc1 : public OS::process<TProc1, OS::pr0, 300>
{
public:
    static void exec()
    {
        for(;;)
        {
            ef.wait();
            PB0.Off();
        }
    }
};

 

Что мы в итоге имеем? 1) Класс, в котором можно инкапсулировать данные и методы процесса. Закрытые и используемые только в TProc1 данные можно объявить в секции private класса и никто к ним не получит доступ. 2) Более привычный способ реализации ф-ции.

 

Кто что думает на этот счёт?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Что мы в итоге имеем? 1) Класс, в котором можно инкапсулировать данные и методы процесса. Закрытые и используемые только в TProc1 данные можно объявить в секции private класса и никто к ним не получит доступ. 2) Более привычный способ реализации ф-ции.

 

Кто что думает на этот счёт?

Во! Я всегда мечтал, чтоб можно было того, инкапсулировать:)

Вопрос только такой: какие изменения были внесены в саму ось, и как это отразилось на размере кода/быстродействии/размере ОЗУ?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

AHTOXA, по идее вообще никак не должно влиять на быстродействие и потребление памяти, т.к. реально дополнительный исполняемый код вообще не добавляется по сравнению с оригинальной версией. Это просто другой способ определить функцию процесса.

 

Выкладываю доработанные файлы в архиве.

Common.zip

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Ну что я могу сказать... Мне очень понравилось. Это именно то, о чём так долго говорили большевики мы с ReAl'ом :)

Проблема только в потере совместимости со всеми существующими проектами.

Будет интересно услышать, что скажут остальные участники.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Необходимость реализовывать функцию процесса внутри поля имён OS,

Откуда взяли, что это необходимость? Не помню, чтобы у меня где-то прикладные процессы жили в пространстве имён OS.

 

а добавление template <> вызывает некоторое удивление :wacko:

Откуда удивление? Это стандартное требование языка С++ - если не указана общая (generic) реализация, будьте добры предоставить специализацию, которую необходимо обозначить в соответсвии с требованиями языка. Функция exeс и является полной специализацией.

 

Подумалось, почему-бы не сделать ф-цию exec просто ф-цией своего собственного класса? На скорую руку сделал несколько изменений в исходниках scmRTOS и весь код декларации и реализации процесса превратился в:

Т.е. в итоге вместо одного template<> нужно создавать каждый раз целый класс. Сомнительне преимущество. Что касается инкапсуляции, то этот принцип можно реализовать и на текущем варианте, только использовав отношение включения вместо отношения наследования, как это сделано у вас.

 

Во! Я всегда мечтал, чтоб можно было того, инкапсулировать:)

Уже обсуждали мы это. Что мешает тебе инкапсулировать, написав обёртку вокруг процесса? В данном случае я вижу появление лишней сущности. Их и так там две - TBaseProcess и process<>, но это сделано из соображений эффективности реализации. А третья добавляется только из синтаксических предпочтений.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Откуда взяли, что это необходимость? Не помню, чтобы у меня где-то прикладные процессы жили в пространстве имён OS.

А как тогда можно сделать без реализации функции процесса внутри namespace OS ? Я просто пока что судил по примерам, которые идут с scmRTOS.

 

Откуда удивление? Это стандартное требование языка С++ - если не указана общая (generic) реализация, будьте добры предоставить специализацию, которую необходимо обозначить в соответсвии с требованиями языка. Функция exeс и является полной специализацией.

Я могу ошибаться, но считается, что уровень познаний в языке программиста который использует библиотеку, обычно меньше, чем уровень знаний того, кто эту библиотеку пишет. Поэтому библиотека может быть сложной внутри, но её использование должно быть простым и понятным. Лично я видел очень небольшое количество С++ библиотек, которые бы заставляли программиста писать специализацию вот таким вот образом, да и то это приходилось делать в очень исключительных случаях. Поэтому и вызывает удивление, что практически базовая функциональность реализована через требование специализации шаблонной функции, которая вызывается библиотекой.

 

Т.е. в итоге вместо одного template<> нужно создавать каждый раз целый класс. Сомнительне преимущество.

Да, именно класс. И в этом преимущество, т.к. класс в с++ - это более универсальная вещь, чем функция.

 

Что касается инкапсуляции, то этот принцип можно реализовать и на текущем варианте, только использовав отношение включения вместо отношения наследования, как это сделано у вас.

Можно пример? Просто я не представляю как это можно сделать без лишних телодвижений.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Уже обсуждали мы это. Что мешает тебе инкапсулировать, написав обёртку вокруг процесса? В данном случае я вижу появление лишней сущности. Их и так там две - TBaseProcess и process<>, но это сделано из соображений эффективности реализации. А третья добавляется только из синтаксических предпочтений.

Да, обсуждали. В тот раз я не смог тебя убедить:)

Но тогда раз предложенное мной решение было связано с дополнительными расходами. А это решение - не влечёт никаких доп. расходов.

Зачем писать обёртку, если можно инкапсулировать всё прямо в классе процесса? Вот как раз-таки обёртка - это лишняя сушность.

Существующий подход позволяет пользователю специализировать только функцию exec(). А предложенный - позволяет полноценно наследовать класс процесса. Какой вариант гибче?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

А как тогда можно сделать без реализации функции процесса внутри namespace OS ? Я просто пока что судил по примерам, которые идут с scmRTOS.

Я не знаю, какие примеры вы смотрели, в моих примерах этого нет и никогда не было, мне даже в голову не приходило помещать функцию процесса в пространство имён OS - ведь функция процесса - это уже прикладной код, а не код ОС. Исключение составляет фоновый процесс Idle, он целиком помещён в пространство имён OS.

 

Я могу ошибаться, но считается, что уровень познаний в языке программиста который использует библиотеку, обычно меньше, чем уровень знаний того, кто эту библиотеку пишет. Поэтому библиотека может быть сложной внутри, но её использование должно быть простым и понятным. Лично я видел очень небольшое количество С++ библиотек, которые бы заставляли программиста писать специализацию вот таким вот образом, да и то это приходилось делать в очень исключительных случаях. Поэтому и вызывает удивление, что практически базовая функциональность реализована через требование специализации шаблонной функции, которая вызывается библиотекой.

Всё правильно, так и есть. И насколько мне известно, scmRTOS использует много людей, которые в плюсах не особенно подготовлены (а немало из них не особенно и стремится постичь глубины С++), им вполне достаточно знать базовый синтаксис использования, основное из которого - это обращение <ObjectName.MemberName>. И уж написать один раз перед функций template<> никакого труда не составляет, при этом совершенно нет необходимости напрягаться по поводу специализаций и прочего.

 

Вы же предлагаете вариант с созданием класса да ещё и не самым тривиальным способом (наследование от шаблона по методу стратегии), тут у пользователя, который писал, пишет и собирается продолжать писать в С-стиле, вопросов возникнет куда больше - ему придётся врубаться в синтаксис определения классов и наследования, создавать свои определения классов и т.д. - словом, писать свой код в С++ стиле по полной программе. Это совсем не то же самое, что просто создать определение функции по образцу и использовать её в привычном С-стиле. Вас смущает слово template<>? А слово OS_PROCESS, которое используются там же, вас не смущает?

 

Да, именно класс. И в этом преимущество, т.к. класс в с++ - это более универсальная вещь, чем функция.

А если в ряде случаев эта универсальность не нужна? Тогда накладяки на пустом месте. Процесс должен предоставлять отдельный асинхронный поток управления, он это делает - предоставляет функцию exec. Больше он ничего не должен. Зачем его нагружать в базовом исполнении, мотивируя гипотетическими фичами? Лишнее это. База есть. Если кому мало - вэлком, можно расширять.

 

Можно пример? Просто я не представляю как это можно сделать без лишних телодвижений.

Очень просто. Если вам или кому-либо ещё хочется иметь функциональность процесса инакпсулиированной в объекте, определите этот объект, сделайте его "процессную" функцию встраиваемой (чтобы вызова не было) и вызывайте её из process<>::exec(). Всё.

 

Существующий подход предоставляет бОльшую гикость и простоту. Можно сделать так, а можно эдак. Далее, по проектированию. Хороший стиль проектирования подразумевает: "одна сущность - один класс". Один процесс очень часто участвует в реализации далеко не одной сущности, поэтому запихивание всех реализаций в один класс процесса выглядит просто данью парадигме программирования. Вышеописанный способ (определение класса и вызов его "процессной" функии из функции процесса) свободен от этого недостатка - можно создать несколько классов этим способом и вызывать их функции из exec. Инкапсуляция на месте, искусственных "привязок" "класс-процесс" нет.

 

Да, обсуждали. В тот раз я не смог тебя убедить:)

Приводимыми агрументами и не удастся. :) Контрагументы, имхо, сильнее.

 

Зачем писать обёртку, если можно инкапсулировать всё прямо в классе процесса? Вот как раз-таки обёртка - это лишняя сушность.

Не более лишняя, чем определение класса в предлагаемом варианте. Скажи, чем отношение наследования лучше отношения включения? В данном конкретном случае. Чем хуже, уже говорилось: в текущем варианте можно юзать функцию процесса, как есть, в С-стиле, можно включить в другой класса, причём двумя способами - отнаследовашись от process<> или вызывая из process<>::exec() функции других классов, которые реализуют принципы инкапсуляции и абстракции, в то время, как предлагаемый вариант предоставляет только один способ - безальтернативно включить весь код процесса в один класс.

 

Существующий подход позволяет пользователю специализировать только функцию exec(). А предложенный - позволяет полноценно наследовать класс процесса. Какой вариант гибче?

Что мешает тебе наследовать от process<>? Хотя я бы так не делал - лучше написать отдельный класс и вызывать его функцию (или функции) из exec.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Я не знаю, какие примеры вы смотрели, в моих примерах этого нет и никогда не было, мне даже в голову не приходило помещать функцию процесса в пространство имён OS - ведь функция процесса - это уже прикладной код, а не код ОС

Я смотрел примеры AVR и Cortex3 для GCC. Там везде ф-ция процесса реализована в namespace OS.

Изменено пользователем ArtDenis

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Я смотрел примеры AVR и Cortex3 для GCC. Там везде ф-ция процесса реализована в namespace OS.

Помещать функцию в пространство имён или не помещать - это личное предпочтение автора примера, ни язык, ни ОС этого не требуют. В других примерах - тот же AVR/IAR, в частности, этого нет.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Помещать функцию в пространство имён или не помещать - это личное предпочтение автора примера, ни язык, ни ОС этого не требуют. В других примерах - тот же AVR/IAR, в частности, этого нет.

Вообще-то она изначально туда помещена, в объявлении. То, что некоторые компиляторы до сих пор позволяют не указывать это в реализации, не выносит exec() из пространства имён OS.

 

Приводимыми агрументами и не удастся. :) Контрагументы, имхо, сильнее.

Или же кто-то просто упёрся:)

 

Не более лишняя, чем определение класса в предлагаемом варианте. Скажи, чем отношение наследования лучше отношения включения? В данном конкретном случае.

А где ты видишь здесь включение? Никакого включения нет. Есть вызов некой функции некоего стороннего объекта из функции exec() другого класса. Какое же это включение?

предлагаемый вариант предоставляет только один способ - безальтернативно включить весь код процесса в один класс.

Опять не так. Что мешает включить какой-то другой объект в класс процесса? Или же, по-нынешнему, вызвать из exec() функции любого другого объекта?

Короче, сплошные профиты от нынешнего варианта. А недостатков я по-прежнему не вижу:)

Что мешает тебе наследовать от process<>? Хотя я бы так не делал - лучше написать отдельный класс и вызывать его функцию (или функции) из exec.

Не помню, но что-то вроде мешает. Не получается, емнимс. Хотя надо попробовать...

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Йоу! Я придумал, как совместить эти два варианта :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:

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Лично я видел очень небольшое количество С++ библиотек, которые бы заставляли программиста писать специализацию вот таким вот образом, да и то это приходилось делать в очень исключительных случаях.
Старые версии компиляторов могли пропускать, но если нужно сделать свою специализацию шаблона, то иначе по стандарту нельзя.

 

Ну что я могу сказать... Мне очень понравилось. Это именно то, о чём так долго говорили большевики мы с ReAl'ом :)
Да-да-да.

 

Проблема только в потере совместимости со всеми существующими проектами.

Будет интересно услышать, что скажут остальные участники.

Вот потому и я вчера промолчал. Кроме «наконец свершилось» всё равно ничего в голову не лезло :-)

 

Вообще-то она изначально туда помещена, в объявлении. То, что некоторые компиляторы до сих пор позволяют не указывать это в реализации, не выносит exec() из пространства имён OS.
Собственно, оно и в примерах появилось в ответ на ругань более свежих версий компиляторов.

 

 

Йоу! Я придумал, как совместить эти два варианта :08:
Да, похоже, так лучше.

Я уж начал было думать про просто параллельное существование нынешнего process и нового. Но это плохо, по сути одно и то же и при модификациях требовало бы менять в двух местах.

 

 

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Йоу! Я придумал, как совместить эти два варианта :08:

Да, удачное решение :) Мне оно в голову не пришло

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Я придумал, как совместить эти два варианта
Выглядит слабочитаемо. Что мешает завести свой потомок TBaseProcess вне пространства имен OS, оставив в покое родной шаблон?

 

class TProc1 : public OS::process<TProc1, OS::pr0, 300>

Тут TProc1 передается как параметр шаблона только для того, чтобы в конструкторе взять адрес его exec. Страдает мое чувство прекрасного. Возможно менее разрушительным будет добавить второй конструктор, который получает адрес exec в качестве параметра? Или сделать этот конструктор с параметром единственным, задав ему значение по умолчанию? А в потомке вызывать с адресом своего exec. Тоже некрасиво - забудешь в потомке описать такой конструктор и компилятор не отловит. Не знаю. Хотя отловит - линкер выругается, что не определен exec() в предке... Но такое сообщение неверно описывает причину ошибки.

 

Как вариант - можно добавить обсуждаемую фичу в Extensions. Именно как отдельного наследника TBaseProcess.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...