Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Альтернативный вариант задания функции процесса
Форум разработчиков электроники ELECTRONIX.ru > Cистемный уровень проектирования > Операционные системы > scmRTOS
ArtDenis
Приветствую.

Начал смотреть scmRTOS. Сразу начал резать глаз способ реализации функции процесса:
Код
typedef OS::process<OS::pr0, 300> TProc1;

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

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

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

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


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

Кто что думает на этот счёт?
AHTOXA
Цитата(ArtDenis @ Nov 10 2012, 19:36) *
Что мы в итоге имеем? 1) Класс, в котором можно инкапсулировать данные и методы процесса. Закрытые и используемые только в TProc1 данные можно объявить в секции private класса и никто к ним не получит доступ. 2) Более привычный способ реализации ф-ции.

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

Во! Я всегда мечтал, чтоб можно было того, инкапсулироватьsm.gif
Вопрос только такой: какие изменения были внесены в саму ось, и как это отразилось на размере кода/быстродействии/размере ОЗУ?
ArtDenis
AHTOXA, по идее вообще никак не должно влиять на быстродействие и потребление памяти, т.к. реально дополнительный исполняемый код вообще не добавляется по сравнению с оригинальной версией. Это просто другой способ определить функцию процесса.

Выкладываю доработанные файлы в архиве.
AHTOXA
Ну что я могу сказать... Мне очень понравилось. Это именно то, о чём так долго говорили большевики мы с ReAl'ом sm.gif
Проблема только в потере совместимости со всеми существующими проектами.
Будет интересно услышать, что скажут остальные участники.
dxp
QUOTE (ArtDenis @ Nov 10 2012, 20:36) *
Необходимость реализовывать функцию процесса внутри поля имён OS,

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

QUOTE (ArtDenis @ Nov 10 2012, 20:36) *
а добавление template <> вызывает некоторое удивление wacko.gif

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

QUOTE (ArtDenis @ Nov 10 2012, 20:36) *
Подумалось, почему-бы не сделать ф-цию exec просто ф-цией своего собственного класса? На скорую руку сделал несколько изменений в исходниках scmRTOS и весь код декларации и реализации процесса превратился в:

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

QUOTE (AHTOXA @ Nov 10 2012, 22:59) *
Во! Я всегда мечтал, чтоб можно было того, инкапсулироватьsm.gif

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

Можно пример? Просто я не представляю как это можно сделать без лишних телодвижений.
AHTOXA
Цитата(dxp @ Nov 11 2012, 09:21) *
Уже обсуждали мы это. Что мешает тебе инкапсулировать, написав обёртку вокруг процесса? В данном случае я вижу появление лишней сущности. Их и так там две - TBaseProcess и process<>, но это сделано из соображений эффективности реализации. А третья добавляется только из синтаксических предпочтений.

Да, обсуждали. В тот раз я не смог тебя убедитьsm.gif
Но тогда раз предложенное мной решение было связано с дополнительными расходами. А это решение - не влечёт никаких доп. расходов.
Зачем писать обёртку, если можно инкапсулировать всё прямо в классе процесса? Вот как раз-таки обёртка - это лишняя сушность.
Существующий подход позволяет пользователю специализировать только функцию exec(). А предложенный - позволяет полноценно наследовать класс процесса. Какой вариант гибче?
dxp
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) *
Да, обсуждали. В тот раз я не смог тебя убедитьsm.gif

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

QUOTE (AHTOXA @ Nov 11 2012, 13:07) *
Зачем писать обёртку, если можно инкапсулировать всё прямо в классе процесса? Вот как раз-таки обёртка - это лишняя сушность.

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

QUOTE (AHTOXA @ Nov 11 2012, 13:07) *
Существующий подход позволяет пользователю специализировать только функцию exec(). А предложенный - позволяет полноценно наследовать класс процесса. Какой вариант гибче?

Что мешает тебе наследовать от process<>? Хотя я бы так не делал - лучше написать отдельный класс и вызывать его функцию (или функции) из exec.
ArtDenis
Цитата(dxp @ Nov 11 2012, 18:02) *
Я не знаю, какие примеры вы смотрели, в моих примерах этого нет и никогда не было, мне даже в голову не приходило помещать функцию процесса в пространство имён OS - ведь функция процесса - это уже прикладной код, а не код ОС

Я смотрел примеры AVR и Cortex3 для GCC. Там везде ф-ция процесса реализована в namespace OS.
dxp
QUOTE (ArtDenis @ Nov 11 2012, 19:43) *
Я смотрел примеры AVR и Cortex3 для GCC. Там везде ф-ция процесса реализована в namespace OS.

Помещать функцию в пространство имён или не помещать - это личное предпочтение автора примера, ни язык, ни ОС этого не требуют. В других примерах - тот же AVR/IAR, в частности, этого нет.
AHTOXA
Цитата(dxp @ Nov 11 2012, 19:00) *
Помещать функцию в пространство имён или не помещать - это личное предпочтение автора примера, ни язык, ни ОС этого не требуют. В других примерах - тот же AVR/IAR, в частности, этого нет.

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

Цитата(dxp @ Nov 11 2012, 18:02) *
Приводимыми агрументами и не удастся. sm.gif Контрагументы, имхо, сильнее.

Или же кто-то просто упёрсяsm.gif

Цитата(dxp @ Nov 11 2012, 18:02) *
Не более лишняя, чем определение класса в предлагаемом варианте. Скажи, чем отношение наследования лучше отношения включения? В данном конкретном случае.

А где ты видишь здесь включение? Никакого включения нет. Есть вызов некой функции некоего стороннего объекта из функции exec() другого класса. Какое же это включение?
Цитата(dxp @ Nov 11 2012, 18:02) *
предлагаемый вариант предоставляет только один способ - безальтернативно включить весь код процесса в один класс.

Опять не так. Что мешает включить какой-то другой объект в класс процесса? Или же, по-нынешнему, вызвать из exec() функции любого другого объекта?
Короче, сплошные профиты от нынешнего варианта. А недостатков я по-прежнему не вижуsm.gif
Цитата(dxp @ Nov 11 2012, 18:02) *
Что мешает тебе наследовать от process<>? Хотя я бы так не делал - лучше написать отдельный класс и вызывать его функцию (или функции) из exec.

Не помню, но что-то вроде мешает. Не получается, емнимс. Хотя надо попробовать...
AHTOXA
Йоу! Я придумал, как совместить эти два варианта 08.gif

Короче, переименовываем в новом варианте 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.gif
ReAl
Цитата(ArtDenis @ Nov 11 2012, 07:00) *
Лично я видел очень небольшое количество С++ библиотек, которые бы заставляли программиста писать специализацию вот таким вот образом, да и то это приходилось делать в очень исключительных случаях.
Старые версии компиляторов могли пропускать, но если нужно сделать свою специализацию шаблона, то иначе по стандарту нельзя.

Цитата(AHTOXA @ Nov 10 2012, 18:31) *
Ну что я могу сказать... Мне очень понравилось. Это именно то, о чём так долго говорили большевики мы с ReAl'ом sm.gif
Да-да-да.

Цитата(AHTOXA @ Nov 10 2012, 18:31) *
Проблема только в потере совместимости со всеми существующими проектами.
Будет интересно услышать, что скажут остальные участники.
Вот потому и я вчера промолчал. Кроме «наконец свершилось» всё равно ничего в голову не лезло :-)

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


Цитата(AHTOXA @ Nov 11 2012, 21:15) *
Йоу! Я придумал, как совместить эти два варианта 08.gif
Да, похоже, так лучше.
Я уж начал было думать про просто параллельное существование нынешнего process и нового. Но это плохо, по сути одно и то же и при модификациях требовало бы менять в двух местах.


Цитата(AHTOXA @ Nov 11 2012, 18:00) *
Не помню, но что-то вроде мешает. Не получается, емнимс.
Exec() в этом унаследованном от шаблона получается другой (перегруженный). А шаблон хочет затолкать куда надо адрес своего, который остается неопределённым.
ArtDenis
Цитата(AHTOXA @ Nov 12 2012, 01:15) *
Йоу! Я придумал, как совместить эти два варианта 08.gif

Да, удачное решение sm.gif Мне оно в голову не пришло
Сергей Борщ
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.
AHTOXA
Цитата(Сергей Борщ @ Nov 12 2012, 13:13) *
Выглядит слабочитаемо. Что мешает завести свой потомок TBaseProcess вне пространства имен OS, оставив в покое родной шаблон?

Почему слабочитаемо? Всего-то добавлен один-единственный параметр шаблона, который должен иметь функцию exec(). Родной шаблон тоже не пострадал, всего лишь получил одного дополнительного предка. С точки зрения результирующего кода - ничего не изменилось абсолютно. С точки зрения интерфейса, предоставляемого OS::process - тоже полная идентичность.
Единственное, что изменилось - добавился альтернативный способ создания процессов в оси. Имхо, сплошной профитsm.gif
Цитата(Сергей Борщ @ Nov 12 2012, 13:13) *
Как вариант - можно добавить обсуждаемую фичу в Extensions. Именно как отдельного наследника TBaseProcess.

Не понимаю, чем оно мешает в том виде, как предлагается сейчас?
Сергей Борщ
QUOTE (AHTOXA @ Nov 12 2012, 09:48) *
Не понимаю, чем оно мешает в том виде, как предлагается сейчас?
Да мне ничем. Главный идеолог против...
AHTOXA
А может мои пламенные речи уже переубедили его? sm.gif
ArtDenis
Цитата(Сергей Борщ @ Nov 12 2012, 13:13) *
Тут TProc1 передается как параметр шаблона только для того, чтобы в конструкторе взять адрес его exec. Страдает мое чувство прекрасного

Так это вполне обычная практика в C++ - передавать в шаблон базового класса свой же тип:
http://en.cppreference.com/w/cpp/memory/en...hared_from_this
Пример оттуда:
Код
struct Good: std::enable_shared_from_this<Good>
{
...
dxp
QUOTE (AHTOXA @ Nov 11 2012, 23:00) *
Вообще-то она изначально туда помещена, в объявлении. То, что некоторые компиляторы до сих пор позволяют не указывать это в реализации, не выносит exec() из пространства имён OS.

Ни разу не так. Помещено туда определение шаблона process, а exec просто объявлена внутри process, и её определение вполне без проблем может быть сделано где угодно.

QUOTE (AHTOXA @ Nov 11 2012, 23:00) *
А где ты видишь здесь включение? Никакого включения нет. Есть вызов некой функции некоего стороннего объекта из функции exec() другого класса. Какое же это включение?

А я и не говорю, что оно здесь есть. Я его и предлагаю взамен наследования на котором вы настаиваете, хотя в наследовании тут смысла вообще почти нет: из-за того, что exeс статическая, никакое наследование не позволит иметь нормальный объект с инкапсулированными данными внутри - это будет просто пространство имён с "регулировкой" уровня доступа, не более.

QUOTE (AHTOXA @ Nov 12 2012, 02:15) *
Йоу! Я придумал, как совместить эти два варианта 08.gif

Короче, переименовываем в новом варианте process в customProcess, а process объявляем вот так:
CODE
        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.gif


QUOTE (Сергей Борщ @ Nov 12 2012, 14:13) *
Выглядит слабочитаемо. Что мешает завести свой потомок TBaseProcess вне пространства имен OS, оставив в покое родной шаблон?

+1.

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

Да, всяко не очень красиво получается. А главное - ради чего?

QUOTE (Сергей Борщ @ Nov 12 2012, 14:13) *
Как вариант - можно добавить обсуждаемую фичу в Extensions. Именно как отдельного наследника TBaseProcess.

Вот это было бы лучше всего. Расширения для того и предназначены, чтобы расширять. Там можно что угодно делать - желающие пусть юзают.

QUOTE (AHTOXA @ Nov 12 2012, 14:48) *
Почему слабочитаемо? Всего-то добавлен один-единственный параметр шаблона, который должен иметь функцию exec(). Родной шаблон тоже не пострадал, всего лишь получил одного дополнительного предка. С точки зрения результирующего кода - ничего не изменилось абсолютно. С точки зрения интерфейса, предоставляемого OS::process - тоже полная идентичность.
Единственное, что изменилось - добавился альтернативный способ создания процессов в оси. Имхо, сплошной профитsm.gif

Не понимаю, чем оно мешает в том виде, как предлагается сейчас?

Ты уже попробовал в реальном коде? Работает? Кодогенерация идентична? Если на все эти вопросы ответ положительный, можно обсудить дальше.

Если хочется нормальной инкапсуляции, то не нужно городить огороды, это делается легко базовыми средствами языка:
CODE
class TSlon
{
    ...
   void exec()
    {
        for(;;) { ... }
    }
   ...
};

template<> void TProc1::exec() { Slon.exec(); }


Имеем полную настоящую инкапсуляцию. Кроме того, слонов тут можно катать сколько угодно. И не только слонов, но и мамонтов, бегемотов и весь остальной зоопарк.

В общем, ждём результатов обкатки в железе предложенного варианта (process : public custom_process<...>).
AHTOXA
Цитата(dxp @ Nov 13 2012, 12:20) *
В общем, ждём результатов обкатки в железе предложенного варианта (process : public custom_process<...>).

Проверил.
Предложенный вариант даёт полностью, до байта совпадающий бинарный файл прошивки. Но я его на всякий случай прогнал в железе. Работает! sm.gif
Вот исправленный OS_Kernel.h: Нажмите для просмотра прикрепленного файла
OS_Kernel.cpp остаётся родной. Прошу попробовать с другими портами, у кого есть время.
ReAl
Цитата(Сергей Борщ @ Nov 12 2012, 09:13) *
Тут TProc1 передается как параметр шаблона только для того, чтобы в конструкторе взять адрес его exec. Страдает мое чувство прекрасного.
А как иначе без вирутальных функций передать в базовый класс функцию потомка?
Каждый процесс существует все равно в единственном экземпляре, все полиморфизмы в статику, шаблонами.


Цитата(dxp @ Nov 13 2012, 08:20) *
хотя в наследовании тут смысла вообще почти нет: из-за того, что exeс статическая, никакое наследование не позволит иметь нормальный объект с инкапсулированными данными внутри - это будет просто пространство имён с "регулировкой" уровня доступа, не более.
А этого (регулировки уровня доступа) мало?
Все процессы существуют в единственном экземпляре, поэтому статическая exec() не пугает.

Цитата(dxp @ Nov 13 2012, 08:20) *
Код
class TSlon
{
    ...
   void exec()
    {
        for(;;) { ... }
    }
   ...
};

template<> void TProc1::exec() { Slon.exec(); }
Этот вот TSlon::exec() перестал быть функцией процесса. Потерял доступ к protected в TBaseProcess. Их там (пока) и немного, но тут уже «страдает чувство прекрасного» у меня.

По поводу сущностей: «предоставлять функцию процесса» -- это задача базового класса процесса. И если про что-то в системе я думаю «это -- процесс», то мне естественно думать «занчит, оно должно біть потомком базового класса процесса».
Ну так вот сижу я и думаю
«так, мне нужен процесс обслуживания индикации»
«другие будут дергать этот процесс такой-то функцией, которая будет помещать запросы в очередь»
«ага, у процесса должна быть очередь»
Но в результате делаю класс процесса, о котором думал (class TSlon) и класс процесса процесса (typedef OS::process<…> TSlonProc).


Цитата(AHTOXA @ Nov 13 2012, 16:06) *
Предложенный вариант даёт полностью, до байта совпадающий бинарный файл прошивки. Но я его на всякий случай прогнал в железе.
Ну :-) Вдруг эти байты только с виду одинаковые :-D

Цитата(AHTOXA @ Nov 13 2012, 16:06) *
OS_Kernel.cpp остаётся родной. Прошу попробовать с другими портами, у кого есть время.
Ой, если не замотаюсь, завтра на работе (оно там в реальной винде живет) проверю с IAR, но только методом file compare. И мне кажется, что тоже разницы должно быть 0.00, и платы все равно нет под рукой.
gcc/avr не вижу смысла проверять, front-end тот же.
ArtDenis
Цитата(dxp @ Nov 13 2012, 12:20) *
Ни разу не так. Помещено туда определение шаблона process, а exec просто объявлена внутри process, и её определение вполне без проблем может быть сделано где угодно.

Это совершенно неверно. Согласно стандарту языка С++, специализация шаблонной функции должно быть выполнено только в том пространстве имён где был объявлен шаблон. То, что некоторые компиляторы допускают иную трактовку, является их ошибкой.
Вот выдержка из стандарта (14.7.3/1):
Цитата
An explicit specialization shall be declared in the namespace of which the template is a member, or, for member templates,
in the namespace of which the enclosing class or enclosing class template is a member. An explicit specialization
of a member function, member class or static data member of a class template shall be declared in the namespace of
which the class template is a member.


В любом случае компиляторы подтянуться к стандарту, код перестанет компилироваться и придётся писать
Код
namespace OS
{
    template <>
    OS_PROCESS void TProc1::exec()
    {
        ...

Сергей Борщ
QUOTE (ReAl @ Nov 13 2012, 17:31) *
А как иначе без вирутальных функций передать в базовый класс функцию потомка?
Через параметр конструктора предка? Но тогда надо переопределять и terminate(), который тоже использует адрес exec.
dxp
QUOTE (AHTOXA @ Nov 13 2012, 21:06) *
Проверил.
Предложенный вариант даёт полностью, до байта совпадающий бинарный файл прошивки. Но я его на всякий случай прогнал в железе. Работает! sm.gif

Молодец!

QUOTE (ReAl @ Nov 13 2012, 22:31) *
А этого (регулировки уровня доступа) мало?

Конечно мало. Тут речь про инкапсуляцию ведут, а оная подразумевает наличие законченного целостного объекта. Но на деле никакого объекта и в помине нет, а есть сборная солянка из статических членов, засунутых в общее пространство имён. Т.е. ни абстракции, ни отделения интерфейса от реализации (т.к. и интерфейса-то никакого нет) - ничего этого нет. За что боремся?

QUOTE (ReAl @ Nov 13 2012, 22:31) *
Все процессы существуют в единственном экземпляре, поэтому статическая exec() не пугает.

Пугать-то не пугает, но и ничего этот подход не даёт.

QUOTE (ReAl @ Nov 13 2012, 22:31) *
Этот вот TSlon::exec() перестал быть функцией процесса. Потерял доступ к protected в TBaseProcess. Их там (пока) и немного, но тут уже «страдает чувство прекрасного» у меня.

А зачем ему этот доступ? Всё, что предназначено для доступа с уровня пользовательской программы, помещено в public секцию, остальное - для внутренних служебных целей. Поэтому разрешение доступа юзеру к этому представлению - это никакое не благо, а дырка в защите. Если там есть что-то, к чему надо дать доступ на уровне прикладного кода, это надо поместить в открытую секцию.

QUOTE (ReAl @ Nov 13 2012, 22:31) *
По поводу сущностей: «предоставлять функцию процесса» -- это задача базового класса процесса.

Не базового класса процесса, а собственно процесса. Базовый класс процесса нужен для повышения эффективности и является "технологическим".

QUOTE (ReAl @ Nov 13 2012, 22:31) *
И если про что-то в системе я думаю «это -- процесс», то мне естественно думать «занчит, оно должно біть потомком базового класса процесса».

Это почему это? Процесс - это транспорт, который выполняет "транспортную" функцию. А уж чем его загрузишь, то он и повезёт. Отождествлять грузовик с перевозимым грузом, является, имхо, не очень удачной идеей.

QUOTE (ReAl @ Nov 13 2012, 22:31) *
Ну так вот сижу я и думаю
«так, мне нужен процесс обслуживания индикации»
«другие будут дергать этот процесс такой-то функцией, которая будет помещать запросы в очередь»
«ага, у процесса должна быть очередь»

А если этот процесс не только обслуживает индикацию, но и, например, клавиатуру опрашивает? Что мешает на одном "автобусе" катать и пионеров, и бабушек? По моему опыту, как раз-таки, нередко один процесс обслуживает более, чем одну сущность.


QUOTE (ArtDenis @ Nov 13 2012, 22:59) *
Это совершенно неверно. Согласно стандарту языка С++, специализация шаблонной функции должно быть выполнено только в том пространстве имён где был объявлен шаблон. То, что некоторые компиляторы допускают иную трактовку, является их ошибкой.
Вот выдержка из стандарта (14.7.3/1):

Вы путаете declaration (объявление) и definition (определение). Также вы путате явную (explicit) специализацию и полную (full) специализацию. Приведённый вами пункт стандарта гласит о том, что если используется явная специализация, то она должна быть объявлена в том же простанстве имён. Но где там сказано, что на должна быть определена в этом пространстве имён? У нас там нигде явной специализации не объявляется.

QUOTE (ArtDenis @ Nov 13 2012, 22:59) *
В любом случае компиляторы подтянуться к стандарту, код перестанет компилироваться и придётся писать
CODE
namespace OS
{
    template <>
    OS_PROCESS void TProc1::exec()
    {
        ...

А этот код - это определение полной (а не объявление явной) специализации функции. Т.ч. всё в порядке, ничего компилироваться не перестанет, пусть там копиляторы хоть подтянутся, хоть отожмутся.
AHTOXA
Ладно, раз уж у Гарри такая идиосинкразия к этому варианту, то давайте сделаем его расширением. Я попробовал, оказывается это работает точно так жеsm.gif
Вот, приаттачу пока сюда, а на днях выложу в репозиторий (Уж здесь-то, я думаю, возражений не последует?).
Нажмите для просмотра прикрепленного файла
И ещё попробую сделать вариант с нестатическим exec(). Тоже в виде расширения. Чтоб уж совсем была инкапсуляцияsm.gif
ReAl
Цитата(dxp @ Nov 13 2012, 18:52) *
Отождествлять грузовик с перевозимым грузом, является, имхо, не очень удачной идеей.
...
Что мешает на одном "автобусе" катать и пионеров, и бабушек?
Давайте только определимся -- грузовик или автобус. И если таки грузовик, то для бабушек с пионерами придётся рядом поставить телегу с креслами и на верёвочке к грузовику прицепить.
Хотя нынешний процесс -- скорее шасси, на которое можно пассажирскую газельку навесить, можно бортовую. Предлагается только вариант на шлее тянуть за этим шасси телегу.

Цитата(dxp @ Nov 13 2012, 18:52) *
Процесс - это транспорт, который выполняет "транспортную" функцию.
Ну да. Только я считаю абсолютно полноправным (равноправным с другими) вариант
Код
class Тгрузовик : public Ттранспорт;
class Тавтобус : public Ттранспорт;
И не считаю, что всегда и везде единственно правильно
Код
class Тгрузовик { public: едь(); };
Ттранспорт<..> транспорт1;
Тгрузовик грузовик;
транспорт1::толкай() { грузовик.едь(); }


Может, я наглухо испорчен борландсишным
Код
class TMyThread : public TThread {
    protected:
        virtual void execute(); // А в этой теме предлагается вместо virtual передать базе тип потомка
но мне это не кажется настолько ненормальным, что нельзя это добавить в саму ОС. Другое дело, если бы это ломало все существующие наработки, но оно же прозрачно для старых проектов.
И не у меня последнего такая хотелка, как видим.
dxp
QUOTE (AHTOXA @ Nov 14 2012, 00:04) *
Ладно, раз уж у Гарри такая идиосинкразия к этому варианту, то давайте сделаем его расширением. Я попробовал, оказывается это работает точно так жеsm.gif
Вот, приаттачу пока сюда, а на днях выложу в репозиторий (Уж здесь-то, я думаю, возражений не последует?).
Нажмите для просмотра прикрепленного файла

Э-э, мы, вроде, договорились, что если реализация не страдает, то принимаем. Т.ч. это можно не расширением, а основным вариантом делать. Клади в trunk, попробуем при случае.

QUOTE (ReAl @ Nov 14 2012, 01:44) *
Хотя нынешний процесс -- скорее шасси, на которое можно пассажирскую газельку навесить, можно бортовую. Предлагается только вариант на шлее тянуть за этим шасси телегу.

Да, скорее просто платформа для перевозки. Проблема в том, она не очень хорошо переделывается ни в полноценный грузовик, ни в автобус (из-за статика).

QUOTE (ReAl @ Nov 14 2012, 01:44) *
Ну да. Только я считаю абсолютно полноправным (равноправным с другими) вариант
CODE
class Тгрузовик : public Ттранспорт;
class Тавтобус : public Ттранспорт;
И не считаю, что всегда и везде единственно правильно
CODE
class Тгрузовик { public: едь(); };
Ттранспорт<..> транспорт1;
Тгрузовик грузовик;
транспорт1::толкай() { грузовик.едь(); }

Да, это хорошая схема, годная, против такой я бы не возражал. Вот если получится это:
QUOTE (AHTOXA @ Nov 14 2012, 00:04) *
И ещё попробую сделать вариант с нестатическим exec(). Тоже в виде расширения. Чтоб уж совсем была инкапсуляцияsm.gif

то тогда в корне пересмотрим подход. Почему там статик, я сейчас уже не помню, то ли что-то не получалось по-иному сделать, то ли тогда видение было таким, идеология. Исторически сложилось. Исходно упор был на минимизацию и лёгкость, нынче времена меняются, можно и основные концепции пересмотреть в каких-то пределах.

QUOTE (ReAl @ Nov 14 2012, 01:44) *
Может, я наглухо испорчен борландсишным
CODE
class TMyThread : public TThread {
    protected:
        virtual void execute(); // А в этой теме предлагается вместо virtual передать базе тип потомка
но мне это не кажется настолько ненормальным, что нельзя это добавить в саму ОС. Другое дело, если бы это ломало все существующие наработки, но оно же прозрачно для старых проектов.
И не у меня последнего такая хотелка, как видим.

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

Что касается самой схемы передачи типа объекта аргументом шаблона, который участвует в наследовании, то это основа для создания стратегий (Александреску). Это достаточно глубокая вещь. В данном же случае это просто синтаксический выверт, и как ты выражаешься: "страдает моё чувство прекрасного". sm.gif Но как уже сказал выше, раз с совместимостью и кодогенерацией никаких проблем нет, пусть будет этот вариант, если он кому-то больше нравится (хотя я не вижу, повторяю, в этом особого смысла - инкапсулированного объекта не получается, придётся руками объявлять все поля-данные вне пределов класса и т.д.).
ArtDenis
Цитата(dxp @ Nov 13 2012, 22:52) *
Вы путаете declaration (объявление) и definition (определение). Также вы путате явную (explicit) специализацию и полную (full) специализацию. Приведённый вами пункт стандарта гласит о том, что если используется явная специализация, то она должна быть объявлена в том же простанстве имён. Но где там сказано, что на должна быть определена в этом пространстве имён? У нас там нигде явной специализации не объявляется.
На самом деле на этот пункт стандарта я вышел погуглив сообщение об ошибке. К сожалению, из той цитаты, что я привёл, действительно не ясно насчёт определения ф-ции.
В общем, задал вопрос на RSDN: http://www.rsdn.ru/forum/cpp/4963144.all. Там есть спецы, знающие стандарт наизусть sm.gif
Сергей Борщ
QUOTE (dxp @ Nov 14 2012, 03:17) *
Почему там статик, я сейчас уже не помню, то ли что-то не получалось по-иному сделать,
Потому что надо получить на него указатель. Если бы там не было static, то указатель был бы на функцию-член, а он совсем другой и зависящий от реализации.
AHTOXA
Цитата(dxp @ Nov 14 2012, 07:17) *
Э-э, мы, вроде, договорились, что если реализация не страдает, то принимаем. Т.ч. это можно не расширением, а основным вариантом делать. Клади в trunk, попробуем при случае.

Да я просто подумал, что незачем заставлять хорошего человека переступать через себя, если есть другой вариант, ничем не хуже. Расширение ничем не отличается в использовании, кроме необходимости добавления строчки #include "CustomProcess.h" в scmRTOS_extensions.h.
Думаю, что это не смертельноsm.gif
В общем, подумай ещё немножко, а я тем временем допилю его (там ещё не охвачен вариант с двумя стеками, и ещё что-то по мелочи), и выложу куда скажешь.
Сергей Борщ
QUOTE (Сергей Борщ @ Nov 14 2012, 09:29) *
то указатель был бы на функцию-член, а он совсем другой и зависящий от реализации.

Рассуждаю.
А если сделать дополнительную статическую функцию, скажем, start(), с параметром типа "тип процесса", в init_stack_frame() использовать ее вместо exec, в стековый фрейм на место регистра, в котором передается параметр, класть this, А функция уже будет делать param->exec(). Т.е. мы не вдаемся в дебри реализации указателя на функцию-член, этим занимается компилятор в start(), exec может быть нестатическим. Как-то так... Еще неплохо бы объявить exec как noreturn, чтобы компилятор догалася заменить вызов exec() на переход в нее. В принципе, такое изменение достойно релиза 4.1. И продумать совместимость с текущими исходниками.
AHTOXA
Давайте я сюда добавлю ссылки на уже придуманные варианты. Вот вариант раз, вот вариант два. Я собственно их и хотел покрутить. Тем более, что с новым параметром шаблона это делать проще.
Сергей Борщ
QUOTE (AHTOXA @ Nov 14 2012, 11:17) *
Я изобрел ведосипед. "Говорят, у дураков мысли сходятся. Но у умных - ЧАЩЕ!"
dxp
QUOTE (Сергей Борщ @ Nov 14 2012, 15:46) *
А если сделать дополнительную статическую функцию, скажем, start(), с параметром типа "тип процесса", в init_stack_frame() использовать ее вместо exec, в стековый фрейм на место регистра, в котором передается параметр, класть this, А функция уже будет делать param->exec(). Т.е. мы не вдаемся в дебри реализации указателя на функцию-член, этим занимается компилятор в start(), exec может быть нестатическим. Как-то так... Еще неплохо бы объявить exec как noreturn, чтобы компилятор догалася заменить вызов exec() на переход в нее. В принципе, такое изменение достойно релиза 4.1. И продумать совместимость с текущими исходниками.

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

P.S. Сам пока этим заниматься не могу, завален по уши текучкой, т.ч. инициативные товарищи - ваша инициатива - ваша реализация. sm.gif Делайте расширение (думаю, сразу в trunk). Кстати, интересный вопрос, можно ли будет использовать гибридную схему - часть процессов по традиционному варианту, часть по новому? Навскидку вижу препятствие - разный способ вызова (напрямую и через указатель). Вот если б можно было совместить этих ужа с ежом, это было бы действительно клёво. Хотя бы тем, что совместимость точно никуда не денется.
ReAl
Цитата(dxp @ Nov 14 2012, 13:57) *
Кстати, интересный вопрос, можно ли будет использовать гибридную схему - часть процессов по традиционному варианту, часть по новому? Навскидку вижу препятствие - разный способ вызова (напрямую и через указатель). Вот если б можно было совместить этих ужа с ежом, это было бы действительно клёво. Хотя бы тем, что совместимость точно никуда не денется.
Когда уже всё в стековом кадре, то все равно должно быть. А вот для формирования...
Отдельно уже проверенные на совместимость process / custom_process, с применением process всё как раньше, но можно отнаследоваться от coustom_process вручную.
Отдельно какой-то process_object, который имеет свою статическую функцию и соответствующая функция для форимрования начального стекового кадра.

Хотя как раз для формирования кадра может быть одна функция, просто принимать два указателя -- на функцию и на аргумент для неё void* типа (или хорошо подумать какого -- у MSP430X ведь слово 16 бит а указатели могут быть длиннее?).

process / custom_process будут передвавть указатель на exec и 0

process_object будет передавать указатель на статическую функцию и this.

Переключателю задач и компании до лампочки, как оно было инициализировано.
ArtDenis
Всё-таки расставлю точки над i по поводу текущего варианта специализации функции процесса. На RSDN мне ответили, что реализация специализации функции шаблонного класса может быть сделана за пределами именованной области где был объявлен шаблон класса, но для этого надо обязательно надо сделать объявление этой специализации функции в той именованной области, где был объявлен шаблон класса.
Т.е. нельзя писать
Код
typedef OS::process<OS::pr0, 200> TestProcess;

template<> void TestProcess::exec()
{
}


Правильно писать так:
Код
typedef OS::process<OS::pr0, 200> TestProcess;

namespace OS
{
    template<> void TestProcess::exec(); // предварительно объявляем в void TestProcess::exec в namespace OS
}

// реализуем void TestProcess::exec в глобальной области видимости
template<> void TestProcess::exec()
{
}


В общем, как-то так
ReAl
Цитата(ArtDenis @ Nov 14 2012, 05:33) *
В общем, задал вопрос на RSDN: http://www.rsdn.ru/forum/cpp/4963144.all. Там есть спецы, знающие стандарт наизусть sm.gif

Ну да.
Только конкретно у gcc где-то нелады и вышло, что
Код
namespace OS {
    template<> TProc1::exec();
}

template<> TProc1::exec()
{
    ...
}
он всё компилирует нормально, но выдаёт предупреждение redundant redeclaration и как предыдущее объявление тычет носом в OS_Kernel.h, в объявление неспециализированной функции в теле
Код
        template<TPriority pr, size_t stack_size>
        class process : public TBaseProcess
        {
        public:
            INLINE_PROCESS_CTOR process();

            OS_PROCESS static void exec();  // <---- вот сюда

Но при этом просто
Код
template<> TProc1::exec()
{
    ...
}
не собирает, тут ему уже того объявления недостаточно.
Вот и вышло, что минимальной кровью так, определение-объявление одним махом:
Код
namespace OS {
    template<> TProc1::exec()
    {
        ...
    }
}
что тоже допускается.
ArtDenis
Цитата(ReAl @ Nov 14 2012, 19:45) *
Ну да.
Только конкретно у gcc где-то нелады и вышло, что
Код
namespace OS {
    template<> TProc1::exec();
}

template<> TProc1::exec()
{
    ...
}

void потерялся. Поэтому и предупреждение вышло.

Тот пример, что я выкладывал сообщением выше компилируется без предупреждений.
ReAl
Цитата(ArtDenis @ Nov 14 2012, 16:00) *
void потерялся. Поэтому и предупреждение вышло.

Ой, ну это я тут из головы забыл, в тексте void есть.
И без него совершенно другая ругань
Код
namespace OS {
   template<> TProc1::exec(); // Строка 161
}

template<> TProc1::exec() // Строка 164
{
    DRIVER(PROC1,OUT);
    DRIVER(TIMER1_TO_PROC1,OUT);
    for(;;) {
        OFF(PROC1);
        Timer1_Ovf.wait();
        ON(PROC1);
        OFF(TIMER1_TO_PROC1);
    }
} // TProc1::exec()
Код
==== Compiling ./src/main.cpp
./src/main.cpp:161:29: error: expected constructor, destructor, or type conversion before ‘;’ token
./src/main.cpp:164:25: error: ISO C++ forbids declaration of ‘exec’ with no type
./src/main.cpp:164:12: error: template-id ‘exec<>’ for ‘int OS::process<(OS::TPriority)0u, 100u>::exec()’ does not match any template declaration

Цитата(ArtDenis @ Nov 14 2012, 16:00) *
Тот пример, что я выкладывал сообщением выше компилируется без предупреждений.
-Wredundant-decls есть?
С ним и с -Wredundant-decls
Код
namespace OS {
   template<> void TProc1::exec(); // Строка 161
}

template<> void TProc1::exec()  // Строка 164
{
    DRIVER(PROC1,OUT);
    DRIVER(TIMER1_TO_PROC1,OUT);
    for(;;) {
        OFF(PROC1);
        Timer1_Ovf.wait();
        ON(PROC1);
        OFF(TIMER1_TO_PROC1);
    }
} // TProc1::exec()
Код
==== Compiling ./src/main.cpp
./src/main.cpp:161:33: warning: redundant redeclaration of ‘static void OS::process<pr, stack_size>::exec() [with OS::TPriority pr = (OS::TPriority)0u, unsigned int stack_size = 100u]’ in same scope
../scmRTOS/Common/OS_Kernel.h:333:36: warning: previous declaration of ‘static void OS::process<pr, stack_size>::exec() [with OS::TPriority pr = (OS::TPriority)0u, unsigned int stack_size = 100u]’
ArtDenis
Цитата(ReAl @ Nov 14 2012, 21:01) *
-Wredundant-decls есть?

Да, с -Wredundant-decls такое-же предупреждение вылезло. Честно говоря даже не знаю что оно означает.
AHTOXA
Я вот что подумал. В момент вызова TBaseProcess::init_stack_frame() у нас уже гарантированно имеется в нужных регистрах указатель на TBaseProcess. Таким образом, ничего формировать не надо, достаточно лишь честно сохранить контекст, подменив PC адресом начала функции-члена exec().
Для пробы можно сделать в конструкторе наследника, как-то так:
Код
class BaseVirtualProcess : public TBaseProcess
{
public:
    INLINE_PROCESS_CTOR BaseVirtualProcess(stack_item_t * StackPoolEnd, TPriority pr)
        : TBaseProcess(StackPoolEnd, pr, 0 // - не нужен)
    {
        reinit_stack_frame();
    }
protected:
    OS_PROCESS virtual void exec() {}; // это наш виртуальный exec()
private:
    void reinit_stack_frame()
    {
        StackPointer += 16;                           // отменим деятельность TBaseProcess::init_stack_frame()
        *(--StackPointer)  = 0x01000000L;             // xPSR
        *(--StackPointer)  = reinterpret_cast<uint32_t>(&exec); // вот здесь адрес виртуального exec
        // и тут честно сохраняем остальные регистры, в том числе и self. (наверное будет ассемблерная процедура в порте)
    }
};

Правда reinterpret_cast здесь не проходит, надо какой-то ещё способ получить адрес exec().

---
Добавлю ссылочку про получение адреса функции-члена. На завтраsm.gif
ReAl
Не надо адрес функции-члена... Слова C++ extensions (а у кого-то может такого расширения не быть) и необходимость выключить предупреждение настораживают.

Лучше со статической функцией и this ей как аргумент. Прозрачнее.
ArtDenis
AHTOXA, Указатель на нестатическую функцию член класса в с++ - это не настоящий указатель. Его структура и размер зависят от компилятора. Поэтому чтобы узнать адрес ф-ции, надо выяснить где именно в структуре этого указателя "сидит" конкретно адрес для перехода.
А зачем вообще нужна нестатическая функция для процесса? Всё равно каждый процесс существует в единственном экземпляре.
AHTOXA
Цитата(ArtDenis @ Nov 16 2012, 09:41) *
AHTOXA, Указатель на нестатическую функцию член класса в с++ - это не настоящий указатель. Его структура и размер зависят от компилятора. Поэтому чтобы узнать адрес ф-ции, надо выяснить где именно в структуре этого указателя "сидит" конкретно адрес для перехода.

Я понимаю это. Потому и говорил не об указателе на функцию-член, а об её адресе. Но вот нестандартность такого решения - это действительно плохо.
Цитата(ArtDenis @ Nov 16 2012, 09:41) *
А зачем вообще нужна нестатическая функция для процесса? Всё равно каждый процесс существует в единственном экземпляре.

Чтобы обращаться к членам класса. Чтобы инициализировать их в конструкторе. Чтобы обращаться к унаследованным функциям класса, в конце концов. Короче, чтоб инкапсуляцияsm.gif

Цитата(ReAl @ Nov 16 2012, 02:19) *
Не надо адрес функции-члена...

Ладно, ладноsm.gif
Сделал вариант с виртуальным exec().
В процессе работы обратил внимание, что TKernelAgent::cur_proc() - private. Мне непонятно такое недоверие к потомкам TKernelAgent:)
Пришлось выкручиваться так:
Код
TBaseProcess* base = const_cast<TBaseProcess*>(get_proc(cur_proc_priority()));

вместо тривиального
Код
TBaseProcess* base = cur_proc();


Обратил внимание, что gcc довольно своеобразно понимает атрибут noreturn. Он перестаёт восстанавливать испорченные регистры, но всё равно сохраняет их! sm.gif
За счёт этого, кстати, вариант с виртуальным exec не проигрывает по стеку варианту с вызовом Slon.exec() из SlonProc::exec().
Хотя нет, всё равно проигрывает. Там же вызов через виртуальный транк...

В общем, вот, смотрите/критикуйте:
CODE
#ifndef VIRTUALPROCESS_H_
#define VIRTUALPROCESS_H_

#include <scmRTOS.h>

namespace OS
{

class BaseVirtualProcess : public TBaseProcess, public TKernelAgent
{
public:
INLINE_PROCESS_CTOR BaseVirtualProcess(
stack_item_t * StackPoolEnd
, TPriority pr
#if scmRTOS_DEBUG_ENABLE == 1
, stack_item_t * aStackPool
#endif
) : TBaseProcess(
StackPoolEnd
, pr
, launch_exec
#if scmRTOS_DEBUG_ENABLE == 1
, aStackPool
#endif
)
{
}
protected:
OS_PROCESS virtual void exec() { for(;;){} };
private:
OS_PROCESS static void launch_exec()
{
for(;;) // eliminate compiler warning
{
TBaseProcess* base = const_cast<TBaseProcess*>(get_proc(cur_proc_priority()));
// TBaseProcess* base = cur_proc(); // private!
BaseVirtualProcess* proc = static_cast<BaseVirtualProcess*>(base);
proc->exec();
}
}
};


template<TPriority pr, size_t stack_size>
class VirtualProcess : public BaseVirtualProcess
{
public:
INLINE_PROCESS_CTOR VirtualProcess()
: BaseVirtualProcess(&Stack[stack_size/sizeof(stack_item_t)]
, pr
#if scmRTOS_DEBUG_ENABLE == 1
, Stack
#endif
)
{
}
private:
stack_item_t Stack[stack_size/sizeof(stack_item_t)];
};

} // namespace OS


#endif /* VIRTUALPROCESS_H_ */
AHTOXA
Я так понимаю, никто не впечатлился? laughing.gif
Да, это очевидно и тривиально, зато переносимо и достигает цели.
Хочу вот что спросить. Почему в этом варианте срабатывает static_cast и не срабатывает reinterpret_cast? Судя по листингу, static_cast вставляет какую-то проверку, и в зависимости от её результата, вызывает разные адреса. В тех описаниях этих *_cast, которые мне попались, ничего про такую интеллектуальность static_cast не было.
Vasya777
Предлагаю другой вариант

Пользовательские классы
Код
class Proc1
{
public:
    OS_PROCESS void exec();
};

class Proc2
{
public:
    OS_PROCESS void exec();
};

class Proc3
{
public:
    OS_PROCESS void exec();
};

Proc1 p1;
Proc2 p2;
Proc3 p3;


Процессы
Код
typedef OS::process<OS::pr0, 300, Proc1, &p1> TProc1;
typedef OS::process<OS::pr1, 300, Proc2, &p2> TProc2;
typedef OS::process<OS::pr2, 300, Proc3, &p3> TProc3;

TProc1 Proc1;
TProc2 Proc2;
TProc3 Proc3;


Функция процесса вызывает конкретную функцию конкретного класса
Код
template<TPriority pr, size_t stack_size, class T, T* p>
OS_PROCESS static void process::exec()
{
    p->exec();
}
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.