OberonCore

Библиотека  Wiki  Форум  BlackBox  Компоненты  Проекты
Текущее время: Четверг, 28 Март, 2024 18:48

Часовой пояс: UTC + 3 часа




Начать новую тему Ответить на тему  [ Сообщений: 54 ]  На страницу Пред.  1, 2, 3
Автор Сообщение
 Заголовок сообщения: Re: Случаи из жизни/практики.
СообщениеДобавлено: Пятница, 04 Октябрь, 2019 18:49 
Аватара пользователя

Зарегистрирован: Воскресенье, 12 Апрель, 2015 18:12
Сообщения: 1134
Откуда: СССР v2.0 rc 1
Я соглашусь с утверждением, что КП со своими расширениями для ООП -- если не на 100%, то очень близко к 100% в моём понимании приблизился к требованиям языка промышленной надёжности.
О7 -- это язык максимально простой и создавался с прицелом на обеспечение 80% потребностей программиста. И модульность О7 здесь зафиксирована как раз на достаточном уровне. Сделать больше -- и компилятор не будет ни маленьким, ни тем более надёжным. Всё, что не влезло в саквояж -- всё в библиотеки. Благо Обороны позволяют и ось написать, и баг не поймать.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Случаи из жизни/практики.
СообщениеДобавлено: Суббота, 05 Октябрь, 2019 13:44 

Зарегистрирован: Воскресенье, 28 Май, 2006 22:12
Сообщения: 1693
Sergej Durmanov писал(а):
Кстати, в а2 есть рекурсивные блокировки

Честно говоря, не помню. Наоборот, как-то помнится, то ли у Мюллера, то ли у Реали, то ли у Фрая, встретилось утверждение, что их нет и, вообще, их использование считается ошибочным на уровне подходов к проектированию. Собственно, я и сам потом получил подтверждение этому в нескольких проектах (правда там всё на pthread реализовывалось или - над голым железом). Замечено было следующее: сначала кажется, что рекурсивный мьютекс решает некоторую проблему "объединения и универсализации" некоего набора функционала. Потом начинают расти количество "прилепок" в виде введения разного рода флагов "учёта состояния". Потом всё это начинает дополняться следующими слоями "заплаток на заплатках". И, естественным образом, происходит смешение уровней проектирования и представления системы и, в итоге, если ЭТО ВСЁ ещё остаётся работоспособным, то оно становится переусложнённой мешаниной.
Тут главное - в определённый момент остановиться и удалить разрешение рекурсивности. Потом, - просто перепродумать и перепроектировать набор методов, чётко разделив "пограничные"/интерфейсные методы, которые, собственно и реализуют монитор Хоара, и - внутренние реализации, вызываемые из нескольких интерфейсных методов. И всё становится стройным и аккуратным. И - главное - ПРАВИЛЬНО спроектированным. А это, поверьте, потом окупается сторицей, хотя в начале может и показаться, что решение получается чуть более "многословным". Но, опять-таки, поверьте, что это - только вначале. Потом оно начинает выигрывать по всем статьям у "заплаточно-мьютекснорекурсивного" решения.

Из недавних примеров я могу привести случай менеджера кучи.
Там есть три типовые интерфейсные классические операции: Alloc, ReAlloc и Free.
Естественно, что в каждой их них необходима работа монитора.
И, если для Alloc и Free всё происходит аккуратно, то для ReAlloc возникает "необходимость" сделать мьютекс в реализации монитора кучи рекурсивным. Почему? Потому, что логика работы ReAlloc, очень красиво выражается через вызовы Alloc и Free. Но они уже имеют внутри себя операцию залочивания мьютекса. Если мы оставим их вызовы внутри ReAlloc "как есть", без залочивания мьютекса внутри самой ReAlloc, то целостность кучи поломается. Поэтому залочивать требуется, потому, что сама логика выполнения операции ReAlloc должна быть "атомарной".
И, естественно, что программист с пониженной социальной ответственностью, ничтоже сумняшеся, просто объявит такой мьютекс, в мониторе кучи, рекурсивным.
Хотя, более правильным является следующее решение:
Мы оставляем в интерфейсных методах менеджера кучи (Alloc, ReAlloc и Free) залочивание и разлочивание мьютекса. А внутри залоченного участка вызываем внутренние реализации методов выделения и освобождения памяти (InnerAlloc и InnerFree).

Это - простой пример. Есть и более сложные, но они - больше по объёму.
В общем.
Простое правило: локирование (например, через мьютекс) внутренностей объекта должно быть ТОЛЬКО в интерфейсных методах. Если, в результате неудачного проектирования (с целью "повторного использования функциональности" внутри методов класса), вы сталкиваетесь с необходимостью сделать мьютекс рекурсивным, значит это - "звоночек" о том, что вы неправильно распределили функционал по интерфейсным и внутренним методам класса.

Заметьте, я постоянно говорю о мьютексах и активностях только в связке с объектами.
По сути, для меня сейчас уже НЕ существует отдельных понятий типа "задача", "поток", "мьютекс" вне привязки и преобразования их в ООП парадигме в "блоки эксклюзивного исполнения" и "активности" при проектировании системы.
Даже - на Си.
Просто уход от перечисленных понятий и внесение их в СВОЙСТВА объектов, а - не отдельных понятий в предметке, совершенно преображает работу и подходы к ней. Становится "чище" и "стройнее" и сама архитектура систем, и - её реализация в виде кода. Уходит масса "нюансов" и "мест, где надо что-то учесть", методы/функции становятся легковеснее в плане семантической нагрузки и чистоты-"одноуровневости", "нагруженности" работой с сущностями и операциями из других уровней представления системы.

Уходите от случая, когда вы мыслите понятиями "потоков", "пулами потоков", "задач", "заданий", "работ", выражаемых через системные потоки, которые "вызывают методы объектов" (которые, в свою очередь, по сути, остаются у вас только хранителями сгруппированных данных).
Вычищайте из описаний системы понятия "поток", "мьютекс", "кондвар"/"переменных условий".
Уводите вниз, их на системный уровень, и делайте их СВОЙСТВАМИ объектов ваших предметных областей.
КАК вы это сделаете - ваша забота и право на творчество.
Я обычно использую свою библиотеку (для Си), в которой у меня реализованы структуры/"классы" Monitor, Activity и - наборы макросов (за которыми прописаны входы и выходы в эксклюзивные секции и ожидание выполнения условия). Иногда это дополняется блокирующими Каналами и Таймерами (их реализация зависит от подлежащего железа и/или ОС). Хотя, в последнее время, я и таймеры для таймаутов делаю СВОЙСТВАМИ конкретных объектов (или мониторов), а не отдельными сущностями. Тайминг — вообще отдельный философский вопрос при проектировании. :)

Кстати, заметил интересную особенность. Надо будет её как-нибудь внимательней рассмотреть.
Так вот: в системах и в коллективах разработчиков, которые делают эти системы, которые тупо работают в старой парадигме потоков-мьютексов-кондваров, где последние рассматриваются как равноправные (а, иногда и ГЛАВНЫЕ) понятия проектируемых систем, очень часто возникает вопрос управления приоритетами потоков/задач/заданий.
А там, где система проектируется на основе активных объектов, такие "проблемы" возникают редко (у меня - вообще никогда не возникали).
Причём, когда на это указываешь, то оппоненты, начинают сильно волноваться и выдвигают в качестве аргументации случаи из своих систем с вопросом: "А КАК ТУТ ИНАЧЕ СДЕЛАТЬ, ЕСЛИ НЕ ВВОДИТЬ ПРИОРИТЕТЫ И НЕ ИЗМЕНЯТЬ ИХ?!"
ДА, действительно, в вашем случае и варианте проектирования системы - НИКАК ИНАЧЕ! :) :) :)
Просто потому, что выбранный вами подход и парадигмы проектирования к этому принуждают.

Второй этап дискуссии неизбежно приходит к фразе: "Ага, какой ты умный! Это ж что - всё перепроектировать?!" :)

Дальше в дискуссии традиционно возникает этап, когда человек может согласиться, что перепроектировать надо, но, при этом, "ничего не меняя". Ибо - «оно же работает!». То есть, человек может согласиться, и - даже проникнуться преимуществами подходов АО, но воспримет это - просто как "налепку ООП-ширм над структурами данных и системными ресурсами".
То есть, допускается традиционная ошибка: те же сами системные ресурсы, служащие для представления исполнимых сущностей и обеспечивающих эксклюзивность доступа к данным, просто оборачиваются в классовые интерфейсы. То есть, как сущности, с которыми оперируют проектировщики и программисты они - НИКУДА НЕ ДЕВАЮТСЯ.
А нам требуется их именно "ДЕТЬ". :)
УБРАВ (низкоуровневые, системные) механизмы реализации элементов многозадачности ИЗ рассмотрения их в предметной области.
"СМЕСТИВ" их из набора самостоятельных, выделенных сущностей проектируемой системы в "область" СВОЙСТВ объектов.

Но народ трудно в эту НЕОБХОДИМОСТЬ врубается.

И все опять, по-новой, продолжают "прыгать за бананом". :)


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Случаи из жизни/практики.
СообщениеДобавлено: Воскресенье, 06 Октябрь, 2019 09:20 

Зарегистрирован: Пятница, 11 Январь, 2019 19:26
Сообщения: 293
Откуда: Russia
Речь о модуле https://github.com/metacore/A2OS/blob/m ... /Locks.Mod, в котором рекурсивные блокировки присутствуют.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Случаи из жизни/практики.
СообщениеДобавлено: Понедельник, 07 Октябрь, 2019 00:53 

Зарегистрирован: Воскресенье, 28 Май, 2006 22:12
Сообщения: 1693
Sergej Durmanov писал(а):
Речь о модуле https://github.com/metacore/A2OS/blob/m ... /Locks.Mod, в котором рекурсивные блокировки присутствуют.

А! я понял, Сергей. Мы с Вами - про разные вещи говорим. :)
Посмотрите на заголовок этого модуля:

MODULE Locks; (** AUTHOR "TF"; PURPOSE "Highlevel locks (recursive, reader writer)"; *)

То, что здесь реализовано - высокоуровневое представление привычных "темплейтов" обеспечения синхронизации доступа к неким элементам данных.
Но, это - то, что "вынесено" явно "наверх".

А теперь посмотрите на строку № 23 в этом же файле. ВИдите там {EXCLUSIVE} ?
Так вот, когда я тут растекаюсь мыслью по древу, я ВСЕГДА имею в виду базовые механизмы обеспечения могозадачности и единственности доступа к внутренним полям объектов "в духе АО".
И - НИЧЕГО ИНОГО (и - выше).

Кстати, может быть создалось впечатление, что я, говоря о своих реализациях библиотек, реализующих АО-подход, семантику и синтаксис для Си/Си++, имею в виду нечто, на что указали Вы?
Так - нет, я - именно реализовывал EXCLUSIVE-блоки, AWAIT-ы и активности.
А, как вы сами понимаете (даже беря за основу указанный вами модуль), на базе реализованных мной примитивов, можно так же написать свои рекурсивные локи. Но я в них надобности не испытывал пока... :) Я же говорю, что стараюсь так перерабатывать архитектуру, что бы они не нужны стали.

Хорошо, что вы ссылку дали! Спасибо.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Случаи из жизни/практики.
СообщениеДобавлено: Понедельник, 07 Октябрь, 2019 01:09 

Зарегистрирован: Воскресенье, 28 Май, 2006 22:12
Сообщения: 1693
Sergej Durmanov писал(а):
...
Вот, просто для иллюстрации, о чём я всё время тут говорю, - два слайда из моего доклада.

Вот то, как выглядит привычный нам код на АО:

Изображение


А вот, что я получаю в моём Си++ коде (в Си - немножко отличается код инициализации-запуска-останова активности в "объекте"), когда использую свою библиотеку:

Изображение


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Случаи из жизни/практики.
СообщениеДобавлено: Вторник, 08 Октябрь, 2019 18:19 

Зарегистрирован: Понедельник, 25 Июнь, 2012 17:26
Сообщения: 473
Швейцарцы в рамках расширения A2, реализующего "lock-free"-механизмы для активных объектов, предполагали ликвидацию ограничения реентерабельности exclusive-секции:
Florian Negele. Combining Lock-Free Programming with Cooperative Multitasking for a Portable Multiprocessor Runtime System (с. 216)
Цитата:
C.14 Reentrant Exclusive Regions

The original Active Oberon report states that an activity cannot enter an ex-
clusive region more than once. Experience with existing Active Oberon pro-
grams has shown however, that this artificial restriction misled developers
into duplicating a lot of protected procedures. The only difference of the
duplicated code is the omission of the exclusive block modifier.

Change: Explicitly allow reentrancy into exclusive regions.

Semantics: The same activity may enter an exclusive region more than
once. The corresponding protected object is locked until the activity
leaves the outermost exclusive block. If the condition of an AWAIT
statement is not satisfied, the lock on the protected object is released
completely.

Example: Whether or not a supercall to an overridden method is actually
valid according to the old semantics, depends on whether the over-
riding as well as the overridden procedures enter an exclusive region
simultaneously. With the relaxed rule, the developer of an overriding
method can always enter an exclusive region if necessary regardless
of whether a subsequent supercall might do the same. It is therefore
not required to know the actual implementation of the overridden
procedure any more:
Код:
TYPE Base = OBJECT
    PROCEDURE Method*;
    BEGIN {EXCLUSIVE}
        ...
    END Method;
END Base;

TYPE Extension = OBJECT (Base)
    PROCEDURE Method*;
    BEGIN {EXCLUSIVE}
        ...
        Method^;
        ...
    END Method;
END Extension;



Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Случаи из жизни/практики.
СообщениеДобавлено: Вторник, 08 Октябрь, 2019 18:21 

Зарегистрирован: Понедельник, 25 Июнь, 2012 17:26
Сообщения: 473
Wlad писал(а):
Так вот: в системах и в коллективах разработчиков, которые делают эти системы, которые тупо работают в старой парадигме потоков-мьютексов-кондваров, где последние рассматриваются как равноправные (а, иногда и ГЛАВНЫЕ) понятия проектируемых систем, очень часто возникает вопрос управления приоритетами потоков/задач/заданий.
А там, где система проектируется на основе активных объектов, такие "проблемы" возникают редко (у меня - вообще никогда не возникали).
Причём, когда на это указываешь, то оппоненты, начинают сильно волноваться и выдвигают в качестве аргументации случаи из своих систем с вопросом: "А КАК ТУТ ИНАЧЕ СДЕЛАТЬ, ЕСЛИ НЕ ВВОДИТЬ ПРИОРИТЕТЫ И НЕ ИЗМЕНЯТЬ ИХ?!"
ДА, действительно, в вашем случае и варианте проектирования системы - НИКАК ИНАЧЕ! :) :) :)
Просто потому, что выбранный вами подход и парадигмы проектирования к этому принуждают.

Wlad писал(а):
Кстати, заметил интересную особенность. Надо будет её как-нибудь внимательней рассмотреть.

Насчёт расширенной политики управления приоритетами (в том числе) было другое расширение A2:
Daniel Keller. Paradigms and tools for developing dependable realtime software


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Случаи из жизни/практики.
СообщениеДобавлено: Вторник, 08 Октябрь, 2019 20:06 

Зарегистрирован: Воскресенье, 28 Май, 2006 22:12
Сообщения: 1693
PSV100 писал(а):
Швейцарцы в рамках расширения A2, реализующего "lock-free"-механизмы для активных объектов, предполагали ликвидацию ограничения реентерабельности exclusive-секции

Это будет ОЧЕНЬ хреновой прилепкой.
Оно поощрит конструктора базового класса "забивать" на детальную его проработку и продумывание.
Здесь, опять-таки, уходят от решения проблемы "разноса" функционала по разным методам (интерфейсной и "внутренне-вызываемой частями).
Одна из основных причин таких глюков на уровне проектирования ("уж сколько раз твердили миру...") - неследование рекомендации выполнять в функции строго одно, логически завершённое (атомарное), действие на данном уровне представления системы.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Случаи из жизни/практики.
СообщениеДобавлено: Среда, 09 Октябрь, 2019 15:59 

Зарегистрирован: Понедельник, 25 Июнь, 2012 17:26
Сообщения: 473
Видимо, в целом язык не очень-то поощряет или слабо способствует иным архитектурным подходам. Отсюда и особенности дизайна системы модульности, о чём пытались дискутировать выше в теме. Оберонам свойственна некая "жёсткая" или "сильно замкнутая" инкапсуляция, что ли..., которая, однако, может иметь свои методологические основания (?). В контексте уровней закрытия наблюдается "лимитированный" доступ (модификатор "-") для операций (только для реализации/определения), но по сравнению с "классическими" паскалевскими модулями, к примеру, в той же Delphi/Freepascal нет аналога "protected" -- элементы доступны (вместе с возможностью самостоятельного вызова/исполнения) только наследникам/расширениям, включая и во внешних модулях -- где традиционно рекомендуется размещать методы вида InnerAlloc, InnerFree и т.п. (согласно примерам выше).
В качестве обоснования для ликвидации ограничения реентерабельности было указано:
Цитата:
Experience with existing Active Oberon pro-
grams has shown however, that this artificial restriction misled developers
into duplicating a lot of protected procedures. The only difference of the
duplicated code is the omission of the exclusive block modifier.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Случаи из жизни/практики.
СообщениеДобавлено: Среда, 09 Октябрь, 2019 16:43 

Зарегистрирован: Пятница, 11 Январь, 2019 19:26
Сообщения: 293
Откуда: Russia
Цитата:
А! я понял, Сергей. Мы с Вами - про разные вещи говорим. :)
Посмотрите на заголовок этого модуля:
тем не менее, это те же самые мьютексы. Языковые сред,тва в этом плане примитивны, поэтому приходится писать дополнительные модули. В зонноне, в дополнение к монопольным секциям реализованы shareable, а в активном обероне это помечено как unimplemented YET. Почему не реализовали в ао? Ну по ому же, почему все остальное в оберонах не реализовано - можно выразить через что-то другое. Через те же самые монопольные области. На а то, что закат солнца вручную, так это не страшно.
В общем, я думаю, что отсутствие реентерабельных мьютексов, скорее недостаток. Ну и они во всех распространенных ос есть.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Случаи из жизни/практики.
СообщениеДобавлено: Среда, 09 Октябрь, 2019 19:28 

Зарегистрирован: Воскресенье, 28 Май, 2006 22:12
Сообщения: 1693
Sergej Durmanov писал(а):
В общем, я думаю, что отсутствие реентерабельных мьютексов, скорее недостаток. Ну и они во всех распространенных ос есть.

Я со своим мнением вас и коллег ознакомил.
Придерживаюсь принципа: "ЕСЛИ ЧТО-ТО МОЖНО СДЕЛАТЬ, ТО ЭТО СОВСЕМ НЕ ОЗНАЧАЕТ, ЧТО ЭТО НУЖНО ДЕЛАТЬ".
Можно и активные объекты образовывать (в Дельфи и Джаве), наследуясь от класса Потока/реализовывая некий интерфейс Выполнимый. Есть куча решений на этом подходе основанных ("все так делают"). Но авторам библиотек и наборов классов, кто позволили такое делать, надо пистон хорошенький вставить за предоставление такой возможности и средств реализации.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Случаи из жизни/практики.
СообщениеДобавлено: Среда, 09 Октябрь, 2019 20:16 

Зарегистрирован: Воскресенье, 28 Май, 2006 22:12
Сообщения: 1693
Sergej Durmanov писал(а):
Цитата:
А! я понял, Сергей. Мы с Вами - про разные вещи говорим. :)
Посмотрите на заголовок этого модуля:
тем не менее, это те же самые мьютексы.
НЕТ, Сергей!
Не воспринимайте это, как "мьютекс"!
Да, "снизу", на системном уровне, это может быть реализовано именно так (и реализуется мной в моей библиотеке для POSIX-систем, на мьютексах и кондварах).
Но, на уровне архитектуры - выбрасывайте всякое упоминание о средствах реализации, пришедших "снизу"!
Забудьте про них!
Я всё время упоминаю мьютексы и кондвары потому, что стараюсь донести принципы до массы программистов, которые уже отравлены понятийным набором, "пропихнутым" из системного уровня в прикладной, через "знакомые" "мейнстриму" аналоги. Но! Это - только аналоги функциональности для объяснения основ и - ничего больше. Сам принцип - ограничить употребление "привычных понятий" или вообще отказаться от них, в пользу совершенно другой терминологии
Все "привычные" понятия из того же POSIX-а - лишь вариант реализации. Причём, реализации, которые дают потенциал для расцвета уродских и плохо разработанных архитектур. Тяп-ляп, потому, что "все так делают" - ото самое.

В АО есть прекрасные, ВЫСОКОУРОВНЕВЫЕ примитивы для отражения СВОЙСТВ объектов быть активным (иметь жизненный цикл) и реализовывать мониторы Хоара-Хансена. Дальше этого - стоп. Забудьте о частных недосредствах реализации того же самого, притащенных из системного уровня. НЕ смешивайте уровни! Продумывайте архитектуру и распределение функционала между методами объекта из вашей предметки и будет вам щасте! :)

Sergej Durmanov писал(а):
Языковые сред,тва в этом плане примитивны, поэтому приходится писать дополнительные модули.
Для "прилепок" - да. Для аккуратных и расширяемых систем - приходится поломать голову. Зато и решения получаются - КОНФЕТКА! Вполне "примитива" а ля АО-стайл хватает. Примитив здесь я употребляю не для уничижительной характеристики.

Sergej Durmanov писал(а):
Через те же самые монопольные области. На а то, что закат солнца вручную, так это не страшно.
Это вы - про EXCLUSIVE-блоки? В чём здесь "закат солнца вручную"??? Я воспринимаю это - как совершенно универсальный, законченный и абсолютно полезный механизм и свойство объекта.

Я уже в который раз повторю: я иду не от средств реализации, кромсая под них задачу, а - от решения задачи наиболее естественным образом. И наборы "примитивов" АО - очень мощное и гибкое решения для подстройки под решение задачи и выражение его в коде наиболее адекватным способом.

Мне уже НЕ нужны "нюансы" работы, притянутых в прикладную область, совершенно чуждых сущностей из системного программирования (потоки, мьютексы, кондвары)! Они начинают диктовать свои законы и "учёт тонкостей реализации". Это всё - не из прикладной области. А их смешивают. Получается винегрет из разных уровней логики и природы выражаемых понятий. А я - далеко не гений и у меня часто в большой системе на всё мозгов не хватает. А вот при эмуляции АО-примитивов, происходит значительное "очищение" кода и разгрузка мышления и представления о задаче от чуждых, и не относящихся непосредственно в данном месте к задаче, сущностей.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Случаи из жизни/практики.
СообщениеДобавлено: Пятница, 18 Октябрь, 2019 17:30 

Зарегистрирован: Воскресенье, 28 Май, 2006 22:12
Сообщения: 1693
Следующий совет (многое само по себе не вспоминается, но на это наталкивают замечания коллег в телеге :) )

Об этом здесь (на форуме) уже упоминалось, но - повторюсь:

1. НИКОГДА НЕ НАСЛЕДУЙТЕСЬ НАПРЯМУЮ ИЛИ КОСВЕННО ОТ ЭЛЕМЕНТАРНЫХ КОНТЕЙНЕРОВ ДЛЯ РЕАЛИЗАЦИИ СУЩНОСТЕЙ ИЗ СВОЕЙ ПРЕДМЕТНОЙ ОБЛАСТИ.
ИСПОЛЬЗУЙТЕ АГРЕГАЦИЮ (ИЛИ КОМПОЗИЦИЮ).

2. НИКОГДА НЕ РЕАЛИЗУЙТЕ И/ИЛИ НЕ ПОЛЬЗУЙТЕСЬ БЛОКИРУЕМЫМИ ("ПОТОКОБЕЗОПАСНЫМИ") ЭЛЕМЕНТАРНЫМИ КОНТЕЙНЕРАМИ И СТРУКТУРАМИ ДАННЫХ.
БЛОКИРОВКАМИ ДОЛЖНЫ "ЗАВЕДОВАТЬ" ВЛАДЕЛЬЦЫ ТАКИХ СТРУКТУР И/ИЛИ КОНТЕЙНЕРОВ.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Случаи из жизни/практики.
СообщениеДобавлено: Среда, 30 Октябрь, 2019 19:08 

Зарегистрирован: Воскресенье, 28 Май, 2006 22:12
Сообщения: 1693
Ещё один совет. Про "максимально возможную обобщённость". В данном случае - интерфейса, через которую задекларирована некая функциональность.
Как пример, на котором рассматривается совет - случай из моей практики. Надо было соединить объект-трейсер с объектом, который работает с коммуникационным интерфейсом.
В объекте-трейсере накапливались сообщения от подсистем (много писателей) и в нём же была своя активность (один читатель).
Сама реализация "накопителя" сообщений, в данном случае, не важна (там и было несколько вариантов испробовано - от простого кольцевого буфера и - вплоть до собственной "мини-кучи", из которой писатели запрашивали участки памяти - не суть важно в нашем случае).

Изначально разработчик, отвечавший за коммуникационные интерфейсы реализовал "драйвер" для UART.
И заявил интерфейсную функцию в таком виде:
Код:
void uart_write( uint8_t ch );
заявив, при этом, что функция - блокирующая, то есть, не "отпускает", пока байт не будет передан.
(попутно выяснилось, что там он даже прерывание по окончанию передачи не использовал, а - "тупо" - становился в цикл проверки бита-флага о готовности на запись в регистр данных UART.
То есть, он "выжирал" время МОЕГО потока из трейсера.
При этом, он ещё никоим образом не информировал мой вызывающий код об успешности операции (но то - такЭ...).

Мной было предложено другое определение функции:
Код:
size_t tracer_consumer_write( tracer_consumer_t* consumer, const void* data, size_t data_size );
причём, я предложил ввести не просто функцию, а сделать её "методом интерфейса" (дело происходит в Си):
Код:
typedef enum tracer_consumer_errors_e
{ tracer_consumer_errors_OK = 0
, tracer_consumer_errors_write_HARDWARE = -1
, tracer_consumer_errors_write_LINK     = -2
, tracer_consumer_errors_write_SINK     = -3
, tracer_consumer_errors_write_SYSTEM   = -4
, ...
} tracer_consumer_errors_t;

typedef size_t (tracer_consumer_write_f*)( tracer_consumer_t* consumer, const void* data, size_t data_size );

typedef struct tracer_consumer_s {
    tracer_consumer_errors_t _error;
    tracer_consumer_write_f  _Write;
}
Однако, начальство настояло на предложении "реализатора" UART-драйвера ("в час по чайной ложке").

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

Какие плюсы внедрения ООП-стила и "интерфейсности"?
В самой функции, при максимальной абстрагированности от природы потребителя данных трейсера, есть возможность его идентификации (а - поверьте, у человека-реализатора драйвера UART, заняло некоторое время выяснить в какой именно UART отправлялись данные).
При этом, нам, в дальнейшем будет абсолютно всё равно, частью какого именно связного интерфейса будет наша "реализация интерфейса ПотребительДанныхТрейсера".
Сама функция (метод) абсолютно обобщён в "предоставляемой операции". через аргументы внутрь потребителя данных передаётся указатель на область памяти и её размер. Возвращаемое значение - количество "воспринятых" потребителем байтов из переданной области данных. Это помогает активности трейсера определиться, с какого места надо передавать данные при следующем вызове метода _write потребителя.
Заметьте, что возвращаемое значение - НЕ код ошибки. Я отказался от такой практики, перенеся "ошибочное состояние" ВНУТРЬ объекта, метод которого был вызван. При желании (а оно есть всегда и всегда удовлетворяется :) ) активность трейсера может проверить поле ошибки потребителя.

Были указания, что потребитель-"драйвер" связного интерфейса может использовать DMA и это накладывает дополнительные ограничения на место в памяти (выравнивание, диапазон разрешённых адресов), на которое указывает второй аргумент предложенной мной функции.
Причём, мои возражения, что приписывание трейсеру не специфических для него обязанностей, АРХИТЕКТУРНО ОШИБОЧНО, были встречены с иронией и сарказмом. То есть, люди, "размазывали" уровни представления системы, но НЕ ПОНИМАЛИ ЭТОГО. Слава Богу, что я-таки "додавил" свой вариант "дополнительной манипуляции с данными" именно на стороне драйверов. Это спасло в дальнейшем от "размножения" вариантов реализации трейсера в зависимости от использующегося связного интерфейса. Сам же трейсер переходил из системы в систему неизменным.

Вроде бы - мелочь, но именно из таких маленьких кирпичиков выращиваются/выстраиваются правильно спроектированные системы.


Вернуться к началу
 Профиль  
 
Показать сообщения за:  Поле сортировки  
Начать новую тему Ответить на тему  [ Сообщений: 54 ]  На страницу Пред.  1, 2, 3

Часовой пояс: UTC + 3 часа


Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 3


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
Вся информация, размещаемая участниками на конференции (тексты сообщений, вложения и пр.) © 2005-2024, участники конференции «OberonCore», если специально не оговорено иное.
Администрация не несет ответственности за мнения, стиль и достоверность высказываний участников, равно как и за безопасность материалов, предоставляемых участниками во вложениях.
Без разрешения участников и ссылки на конференцию «OberonCore» любое воспроизведение и/или копирование высказываний полностью и/или по частям запрещено.
Powered by phpBB® Forum Software © phpBB Group
Русская поддержка phpBB