реклама на сайте
подробности

 
 
17 страниц V  « < 14 15 16 17 >  
Reply to this topicStart new topic
> Система, управляемая событиями и SST(super-simple tasker), Выделено из "ООП. Классы и динамические объекты"
XVR
сообщение Sep 30 2016, 19:48
Сообщение #226


Гуру
******

Группа: Свой
Сообщений: 3 123
Регистрация: 7-04-07
Из: Химки
Пользователь №: 26 847



Цитата(amaora @ Sep 30 2016, 17:39) *
Нужно было сделать запрос и подождать готовности ответа, в частности функция i2c_read. Ничего лучше двух мьютексов не нашлось. На захвате первого ждем готовности интерфейса, на втором готовности ответа. Только второй примитив не мьютекс, а семафор. Можно как-то лучше?
Это зависит от того как вы в дальнейшем используете результат (в частности нужен ли он в этом потоке, или можно сделать асинхронный callback), и используется ли еще где то работа с этой самой i2c шиной (или с теми ресурсами, которые нужны для такой работы). И если да, то можно ли собрать всю эту работу в одно место?


Go to the top of the page
 
+Quote Post
brag
сообщение Sep 30 2016, 20:21
Сообщение #227


Профессионал
*****

Группа: Свой
Сообщений: 1 047
Регистрация: 2-12-06
Из: Kyiv, Ukraine
Пользователь №: 23 046



Цитата
Для этого обычно используют примитивы захвата с timeout'ом

A если надо таймаут не на захват одного ресурса, а на несколько? Не спорю, на потоках тоже можно реализовать, на на SST это проще.
Та же задача с атомным реактором - считываем группу датчиков, если не успели за 5 сек - срабатывает высокоприоритетное событие, которое задвинет стержни и потушит реакцию. С очередями аналогично - вдруг где-то что-то в очередь не влезло - срабатывает событие, которое гарантировано(при любых раскладах) задвинет стержни. Для таких ответственных задач нужна статическая память(то есть гарантия ее наличия еще на этапе компиляции) - никаких стеков и куч и event-ы - никаких сложных планировщиков. И проверенные временем высокоурвневые обьекты - без ручной работы с памятью, иначе будет высокая вероятность схватить segfault - от человеческого фактора никто не застрахован.

Цитата
Вы опять путаете причину со следствием. Динамические приоритеты появились не потому что планировщик в ОС такой сложный, а именно такой сложный планировщик появился потому, что возникла потребность в динамических приоритетах.
Кстати, очередь с приоритетами не аналогична приоритетам задач в планировщике ОС. Если в очередь поставить задачу с меньшим приоритетом, а потом постоянно добавлять задачи с большим, то задача с меньшим приоритетом никогда не исполнится. А ОС все же будет исполнять задачу с меньшим приоритетом.

Ну да, в SST аналогично - если будет флуд высокоприоритетных событий - низкоприоритетные никогда не запустятся. Если такое поведение не подходит - тогда нужна ОС со сложным планировщиком. Обычно в таких ОС о приоритетах никто уже не задумывается - приоритеты динамически расставляет сама ОС

Цитата
Для STM32F407 уже можно и обычную ОС (типа scmRTOS или freertos), памяти у него хватит, а заниматься переучиванием себя под SST выйдет дороже. Использование SST в этом случае оправданно если вы эксперт в ней, и у вас уже есть большие наработки, и event drive стиль для вас привычен. Но на этом форуме похоже вы один такой

Да, нужно иметь опыт в even-driven. Много памяти - это очень удобно для SST - можно смело использовать динамическую память (кучи или пулы блоков фиксированных длин), там, где это уместно - тогда начинаешь чувствовать себя, как в Javascript-е sm.gif

Цитата
Я где-то здесь недавно задавал вопрос. Нужно было сделать запрос и подождать готовности ответа, в частности функция i2c_read. Ничего лучше двух мьютексов не нашлось. На захвате первого ждем готовности интерфейса, на втором готовности ответа. Только второй примитив не мьютекс, а семафор. Можно как-то лучше? На очередях получается, еще сложнее.

А зачем ждать готовности интерфейса? Добавили запрос в очередь. Как только дойдет до него дело(а раз дошло, значит шина уже свободная) - он выполнится и по завершению выдаст соответствующий event. В любом контроллере есть для этого соответствующие прерывания.
Та даже если и нет, а работаем с шиной вручную дрыганием ног - все точно так же - достали из очереди запрос, выполнили, выкинули соответствующий event. Почему просто не выполнить это без всяких очередей - потому что с SST можно выполнять работу с дрыганием ног в своем приоритете, чтобы и другим не мешать, и чтобы глюков(задержек клока итп) на шине не было, из за того, что кто-то прервал нашу работу.
Такие задачи работы с аппаратурой на SST и очереди ложатся, как влитые.
Go to the top of the page
 
+Quote Post
amaora
сообщение Sep 30 2016, 20:48
Сообщение #228


Местный
***

Группа: Участник
Сообщений: 421
Регистрация: 2-01-08
Пользователь №: 33 778



Цитата(XVR @ Sep 30 2016, 22:48) *
Это зависит от того как вы в дальнейшем используете результат (в частности нужен ли он в этом потоке, или можно сделать асинхронный callback), и используется ли еще где то работа с этой самой i2c шиной (или с теми ресурсами, которые нужны для такой работы). И если да, то можно ли собрать всю эту работу в одно место?


Нужен в этом потоке. Вызов к i2c может произойти из 2-3 потоков, с разной частотой или нерегулярно. В одно место собрать можно, если захотеть. Но вопрос именно в том как делать подобные блокирующие вызовы а не избавится от них. Например, при чтении/записи файлов не те же проблемы возникнут?

Цитата(brag @ Sep 30 2016, 23:21) *
А зачем ждать готовности интерфейса? Добавили запрос в очередь. Как только дойдет до него дело(а раз дошло, значит шина уже свободная) - он выполнится и по завершению выдаст соответствующий event. В любом контроллере есть для этого соответствующие прерывания.
Та даже если и нет, а работаем с шиной вручную дрыганием ног - все точно так же - достали из очереди запрос, выполнили, выкинули соответствующий event. Почему просто не выполнить это без всяких очередей - потому что с SST можно выполнять работу с дрыганием ног в своем приоритете, чтобы и другим не мешать, и чтобы глюков(задержек клока итп) на шине не было, из за того, что кто-то прервал нашу работу.
Такие задачи работы с аппаратурой на SST и очереди ложатся, как влитые.


Вопрос был не про SST, на нем задача решится, не сомневаюсь. Проблема только в том, что в C это будет callback hell, а на более другие языки пока нет желания переходить.

А каким образом вы делаете выход из PendSV обработчика на Cortex-M* когда надо после него вызвать обработку события? Где-то упоминали, я не понял.
Go to the top of the page
 
+Quote Post
brag
сообщение Sep 30 2016, 21:46
Сообщение #229


Профессионал
*****

Группа: Свой
Сообщений: 1 047
Регистрация: 2-12-06
Из: Kyiv, Ukraine
Пользователь №: 23 046



Цитата
Вопрос был не про SST, на нем задача решится, не сомневаюсь. Проблема только в том, что в C это будет callback hell, а на более другие языки пока нет желания переходить.

Если грамотно разложить на функции, то hell-a не будет. Наоборот в C есть вложенные функции, а в C++ их нет sad.gif Правда есть лямбды, недавно появились относительно.
Сахарку можно добавить в С с помощью макросов, если нужно.
А можно(я так иногда делаю) прогонять исходник через скрипт на Python-е(или что больше по душе) - расширять сишный синтаксис своими фантазиями wink.gif Иногда мучаюсь с шаблонами, макросами неделю, потом плюю на все стандарты, беру питон и решаю задачу за 10 минут.
Но согласен, без мощного языка работать с event-ами напряжно и лень пробирает sm.gif

Цитата
А каким образом вы делаете выход из PendSV обработчика на Cortex-M* когда надо после него вызвать обработку события? Где-то упоминали, я не понял.

На ассемблере, довольно хитрым, хотя может и не совсем sm.gif
CODE
__attribute__((naked)) void ePendSV(){
asm volatile(
// push = ldmia; pop = stmdb
// "push {r0,r4-r11, lr} \n" // not necessary, callee saved
// create new stack frame for scheduler
"mov r2, %0 \n" // PSR
"movw r1, #:lower16:SST_sync_scheduler \n" // PC
"movt r1, #:upper16:SST_sync_scheduler \n"
"movw r0, #:lower16:async_scheduler_return \n" // LR
"movt r0, #:upper16:async_scheduler_return \n"
"push {r0, r1, r2} \n" // push {lr, pc, xPSR}
"sub sp, #5*4 \n" // push {r0,r1,r2,r3,r12} - undefined values
// return from exception to scheduler
"bx lr \n"
: :"i"(xPSR_RESET_VALUE));
}

// return to preemtded task through SVC
extern "C" __attribute__((naked)) void async_scheduler_return(){
asm volatile("svc #0");
}

__attribute__((naked)) void eSVCall(){
asm volatile(
//"mov r0, sp \n"
//"bl dump_stack \n"
// kill current stack frame
"add sp, #8*4 \n"
// "pop {r4-r11, lr} \n" // not necessary
// perform an EXC_RETURN (unstacking)
"bx lr \n"
);
}

Смысл в чем - при входе в PendSV создаем кадр стека, кидаем туда адрес функции-планировщика и адрес возврата из этой функции(туда попадем, когда планировщик отработает).
По адресу возврата лежит единственная инструкция - SVC, которая кинет нас в другой обработчик, там нам нужно убрать после себя - удалить наш кадр стека, и таким образом при выходе из этого обработчика мы попадем туда, откуда ранее попали в pendSV.
Этот механизм нужен только для асинхронного прерывания задачи, то есть при добавлении задачи в очередь из прерываний.
Чтобы вызвать планировщик из прерывания(а это делается автоматически после добавления задачи в очередь) достаточно установить PendSV, и по завершению обработки всех прерываний мы попадем в наш хитрый pendsv. Сам pendsv тоже может быть прерван в любой момент - это абсолютно безопасно.
Синхронное прерывание задачи - это просто вызов функции sm.gif

На кортексе я добавил рантайм-сахара, чтобы не задумываться откуда вызывается планировщик - из прерывания или Thread-mode, тк для меня, что прерывание, что любой другой код - это одно и то же - прерывание точно такая же задача, как и все остальные, имеет свой приоритет, только этот приоритет всегда выше приоритетов обычных задач(не-прерываний).
Код
// invoke sync or async scheduler
void SST::choose_and_invoke_scheduler(){
    uint32_t psr;
    __asm volatile("mrs %0, IEPSR" :"=r"(psr));

    if((psr&0x1FF) == 0){ // Thread mode
        SST_sync_scheduler(); // тупо вызов функции
    }else{ // Handler mode
        PendSVset(); // установка флага pendSV
    }
}



Без очередей сериализация доступа к аппаратуре может превратиться в мрак. Допустим есть шина I2C.
Ок, для сериализации нам нужен мютекс, назовем его i2c_mutex.
На этой шине висит 5 устройств. Для сериализации доступа к ним нам опять нужно 5 мютексов device_mutex_X.
Дальше одно из устройств - память, часть из которой просто буфер, а другая часть хранит настройки(тн. Settings), для сериализации нам опять нужно 2 мютекса flash_buffer_mutex и settings_mutex.

Получается, чтобы прочитать какой-нибудь setting нам нужно:
1. схватить settings_mutex
2. схватить device_mutex_memory
3. схватить i2c_mutex
4. что-то сделать
5. отпустить i2c_mutex
6. отпустить device_mutex_memory
7. если нужно - перейти к п2.
8. отпустить settings_mutex
Мало того, работа с i2c будет скорее всего выполняться(хотя бы частично) из прерываний, а для этого нам понадобится еще и семафор.

Это еще довольно простой случай. До dead-locka тут еще далеко(хотя не факт), но вот resource starvation при таком обилии локов будет однозначно, если шина нагружена. Ну и оверхед на мютексы, в реализации самих мютексов по любому будут очереди(гыsm.gif и блокировки.
А если вдруг захочется прочитать setting при работе с устройством X на i2c шине, что будет? Правильно, можно схватить deadlock(раз в неделю/месяц/год).
Можно, конечно, всю работу устройств на i2c покрыть одним жирным мютексом(а не это кучей мютексов), но это во первых ослабляет инкапсуляцию, а во вторых - это тормоза, шина будет простаивать во время обработки данных с флешки.

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

К стати такая динамическая ОС тоже может быть чисто асинхронной (event-driven), но это будет уже не SST, a SCT - Super Complex Tasker sm.gif
Но не на столько complex, как обычная ОС. Если потоки будут без блокировок(но с тайм-квантами и динамическими приоритетами), то такой планировщик проще, тк поток никогда не блокируется, он может быть только вытеснен другим потоком, так, как это происходит в SST.

ps. Изначально на Javascript асинхронный стиль был вынужденной мерой. WEB-приложения становились все сложнее и сложнее. Потом народ просек, что этот стиль довольно крут и придумал NodeJS, чтобы писать в том же стиле и серверы(да и просто прикладной софт), которые раньше делались на блокирующем PHP sm.gif
Go to the top of the page
 
+Quote Post
XVR
сообщение Oct 1 2016, 13:34
Сообщение #230


Гуру
******

Группа: Свой
Сообщений: 3 123
Регистрация: 7-04-07
Из: Химки
Пользователь №: 26 847



Цитата(amaora @ Sep 30 2016, 23:48) *
Нужен в этом потоке. Вызов к i2c может произойти из 2-3 потоков, с разной частотой или нерегулярно. В одно место собрать можно, если захотеть. Но вопрос именно в том как делать подобные блокирующие вызовы а не избавится от них.
brag прав - тут напрашивается сериализация (например с помощью очереди). Если работу с самой I2C шиной можно собрать в одну процедуру (или набор процедур), то сериализацию можно встроить в них. Таким образом на уровне интерфейса ее видно не будет. Еще можно саму работу с I2C разбить на автомат и поместить в прерывания. Вариант в 2мя мьютексами рожалуй самый простой, но его надо очень внимательно изучить на предмет гонок, и в особенности в части синхронизации проверок состояния I2C аппаратуры и ожидания на мьютексах - можно словить deadlock.
Цитата
Например, при чтении/записи файлов не те же проблемы возникнут?
Возникнут. Вариантов решений много - начиная от запрета одновременных обращений из разных потоков к файлам, и заканчивая асинхронным вводом/выводом и сериализацией на уровне ОС

Кстати, для обращения к I2C тоже есть одно простое решение - все обращение должно происходить из одного потока (или из прерываний). Остальные должны отправлять в этот поток запросы, можно поштучно (такая вырожденная очередь получается)


Цитата(brag @ Oct 1 2016, 00:46) *
Если грамотно разложить на функции, то hell-a не будет. Наоборот в C есть вложенные функции, а в C++ их нет sad.gif
В С их нет. Они есть в gcc, но это его собственное расширение (для С)

Go to the top of the page
 
+Quote Post
brag
сообщение Oct 1 2016, 16:33
Сообщение #231


Профессионал
*****

Группа: Свой
Сообщений: 1 047
Регистрация: 2-12-06
Из: Kyiv, Ukraine
Пользователь №: 23 046



Цитата
В С их нет. Они есть в gcc, но это его собственное расширение (для С)

Да, действительно, с C их нет. как-то довелось их применять и компилятор схавал, поэтому и подумал, что они есть в C.
Тогда энкапсулировать можно на уровне файлов. i2c движок не сложный, использовать указатели на функции и typedef, на C норм код получиться.
Go to the top of the page
 
+Quote Post
amaora
сообщение Oct 1 2016, 18:28
Сообщение #232


Местный
***

Группа: Участник
Сообщений: 421
Регистрация: 2-01-08
Пользователь №: 33 778



Цитата(brag @ Oct 1 2016, 00:46) *
Смысл в чем - при входе в PendSV создаем кадр стека, кидаем туда адрес функции-планировщика и адрес возврата из этой функции(туда попадем, когда планировщик отработает).
По адресу возврата лежит единственная инструкция - SVC, которая кинет нас в другой обработчик, там нам нужно убрать после себя - удалить наш кадр стека, и таким образом при выходе из этого обработчика мы попадем туда, откуда ранее попали в pendSV.
Этот механизм нужен только для асинхронного прерывания задачи, то есть при добавлении задачи в очередь из прерываний.
Чтобы вызвать планировщик из прерывания(а это делается автоматически после добавления задачи в очередь) достаточно установить PendSV, и по завершению обработки всех прерываний мы попадем в наш хитрый pendsv. Сам pendsv тоже может быть прерван в любой момент - это абсолютно безопасно.
Синхронное прерывание задачи - это просто вызов функции sm.gif


Почитал programming manual, стало ясно, но сложно, хочется проще.

Цитата
brag прав - тут напрашивается сериализация (например с помощью очереди). Если работу с самой I2C шиной можно собрать в одну процедуру (или набор процедур), то сериализацию можно встроить в них. Таким образом на уровне интерфейса ее видно не будет. Еще можно саму работу с I2C разбить на автомат и поместить в прерывания. Вариант в 2мя мьютексами рожалуй самый простой, но его надо очень внимательно изучить на предмет гонок, и в особенности в части синхронизации проверок состояния I2C аппаратуры и ожидания на мьютексах - можно словить deadlock.


Сама работа с i2c уже на автомате в прерывании. Снаружи только запуск передачи и получение результата. Проверки занятости i2c нет, если мьютекс не взят то предполагается, что i2c не занят, ставим указатель на структуру i2c_request и запускаем прерывание, ждем семафор.

Можно спланировать использование i2c так, чтобы запросы группировались и шли регулярно с некоторой частотой. К некоторым устройствам на каждый такт, к другим лишь иногда. Но это усложнит код использующий i2c и возможно повысит его связность с кодом i2c, в зависимости от деталей. Будут запросы на чтение, а потом рассылка результатов. Обработать все результаты в одной задаче нельзя, разная частота, разные приоритеты.
Go to the top of the page
 
+Quote Post
brag
сообщение Oct 1 2016, 19:15
Сообщение #233


Профессионал
*****

Группа: Свой
Сообщений: 1 047
Регистрация: 2-12-06
Из: Kyiv, Ukraine
Пользователь №: 23 046



С мютексом можно работать, но если начнутся вложенные мютексы - пора переходить на очереди...
К стати как с семафором из прерывания работа выполняется? Через очередь или через блокировку всех прерываний?

Цитата
Почитал programming manual, стало ясно, но сложно, хочется проще.

Проще не будет, кортекс не поддерживает рекурсивные прерывания, поддерживает только вложенные. А для SST нужна рекурсия: задача->планировщик->задача->планировщик->задача итд.
Go to the top of the page
 
+Quote Post
amaora
сообщение Oct 1 2016, 19:37
Сообщение #234


Местный
***

Группа: Участник
Сообщений: 421
Регистрация: 2-01-08
Пользователь №: 33 778



Цитата(brag @ Oct 1 2016, 22:15) *
С мютексом можно работать, но если начнутся вложенные мютексы - пора переходить на очереди...
К стати как с семафором из прерывания работа выполняется? Через очередь или через блокировку всех прерываний?

Проще не будет, кортекс не поддерживает рекурсивные прерывания, поддерживает только вложенные. А для SST нужна рекурсия: задача->планировщик->задача->планировщик->задача итд.


Во FreeRTOS есть xSemaphoreGiveFromISR, она внутри реализована через очередь (базовый примитив, через него все остальные) с одним элементом нулевого размера, а работа с очередью скорее всего содержит в себе запрет прерываний до некоторого приоритета.
Go to the top of the page
 
+Quote Post
brag
сообщение Oct 2 2016, 10:33
Сообщение #235


Профессионал
*****

Группа: Свой
Сообщений: 1 047
Регистрация: 2-12-06
Из: Kyiv, Ukraine
Пользователь №: 23 046



На кортексе можно обойтись без запрета прерываний, у меня именно так планировщик был сделан в моей блокирующей ОС(которой я сейчас не пользуюсь, тк перешел на неблокирующий SST).

Вот процедура добавления syscall-a из прерывания в очередь. Стиль еще старый сишный sm.gif
CODE
int srqEnqueue(uint32_t svc, uint32_t r0, uint32_t r1){
// конкурентное резервирование места под syscall в очереди - без блокировок
uint32_t t, newtail;
do{
uint32_t h = dsrQueue.head;
t = __ldrexh(&dsrQueue.tail); // по этому индексу t будем писать данные, если получиться
newtail = (t+1)&(Srq::size-1);
if(newtail==h)return Error::QUEUE_FULL;
}while(__strexh(newtail, &dsrQueue.tail) );

// все, место удалось зарезервировать, теперь пишем туда данные
Srq::qitem *qi = &dsrQueue.data[t];
qi->svc = svc;
qi->r0 = r0;
qi->r1 = r1;

// выгрузка и выполнение syscall-ов из очереди происходит в PendSV
// у него самый низкий приоритет изо всех прерываний, поэтому в нем тоже блокировок нет
PendSVset();
return 0;
}

// Сама выгрузка и выполнение выглядит вот так.
void Srq::DequeueRun(){
while(1){
uint32_ h = head; // эта head переменная volatile, это важно
if(tail==h)break;
svcTable[data[h].svc](reinterpret_cast<ExceptionStackFrame*>(&data[h])); // собственно виполнение
head = (h+1)&(size-1); // make item available for writing
}
}
// Блокировки тут не нужны, тк запись head происходит только здесь и она не конкурентная

Этот код проверен анализатором и много раз прокручен разными мозгами, можно с у веренностью сказать, что гонок в нем нет, но при соблюдении условий:
1. PendSV не должен прерывать другие прерывания, которые пишут в очередь.
2. Планировщик и вся остальная работа ОС(мютексы итд) тоже должна выполняться только из PendSV(или из такого же уровня приоритета), то есть быть не конкурентной

Для SST такая очередь не годится, там чтение и запись - конкурентные. Там нужна гораздо более сложная, шаблонная, lock-free очередь, ну или на локах, но локи должны покрывать только работу с метаданными(2 указателя), иначе будут тормоза - задержка обработки особо критических прерываний. Такая очередь на локах тоже довольно не тривиальна и требует тщательной отладки. Но делается это один раз.


С event-driven мы уже научились работать sm.gif, теперь нужно двигаться дальше, тк асинхронщина - это путь к функциональному стилю. Чисто ФП-язык(Haskell, Erlang,...) на мк уровня LPC175x/STM32F10x использовать для практических RT-задач вряд ли получится, МК слишком слабые для этого, поэтому придется пользоваться тем, что есть. Это на данный момент C++14 и Rust.
Введение в ФП-асинхронщину тут https://www.fpcomplete.com/blog/2012/06/asy...tinuation-monad
Но для начала на Haskell пописать все таки придется, без этого никак. Вот по этому туториалу учился(и учусь) я http://learnyouahaskell.com/introduction#about-this-tutorial
А тут, интересные, на мой взгляд, практические рекомендации, как применять ФП на C++(14):
http://cpptruths.blogspot.com/2014/03/fun-...yle-part-1.html
http://cpptruths.blogspot.com/2014/05/fun-...yle-part-2.html
http://cpptruths.blogspot.com/2014/08/fun-...yle-part-3.html
Go to the top of the page
 
+Quote Post
brag
сообщение Oct 10 2016, 17:09
Сообщение #236


Профессионал
*****

Группа: Свой
Сообщений: 1 047
Регистрация: 2-12-06
Из: Kyiv, Ukraine
Пользователь №: 23 046



В процессе написания очередного проекта столкнулся с частыми пропусками ошибок добавления в очередь (человеческий фактор однако).
Код
void f(...,const delegate<void()>& cbk){
// ...
   SST::postMessage(cbk);
}

Вместо:
Код
bool f(...,const delegate<void()>& cbk){
//...
   if(SST::postMessage(cbk)){
      return true;
   }else{
//...
      return false;
   }
}

Ну и последующей обработки этих ошибок.

Поэтому изменил паттерн исполняемого обьекта, добавляемого в очередь.
Код
typedef VdelegateFIFO<void(Error)> TEventQueue;

Движок очереди автоматически вызовет callback(Error::QueueFull) если нет места в очереди.

Сам класс Error:
CODE
class Error{
public:
enum E{
NoError = 0,
QueueFull = 1<<(sizeof(int)*8-1),

last_
};

Error(int e): value_(static_cast<E>(e)){}

bool isError()const{ return value_ < 0; }
operator bool()const { return isError(); }

private:
E value_;
};


От Error можно наследоваться, хоть и кривовато, но что поделаешь, C++ однако еще тот sad.gif
CODE
class DerivedError : public Error{
public:
enum E{
first_ = last_-1,

Error1,
Error2,

last_
};

using Error::Error;
};


Ну и добавляется сообщение в очередь таким способом:
Код
void f(...,const delegate<void(Error)>& cbk){
//...
   SST::postMessage(cbk);
}


Ошибку подлавливаем уже в обработчиках
Код
f([this](Error e){
   if(e){ handle_error(e); return; }
});

Если ошибку не обработать - компилятор об этом напомнит, это очень сильно помогает. Мало того, поскольку в SST нет блокировок - раскрутка стека происходит автоматически и бесплатно, в отличии от синхронных исключений C++. А обработка ошибок практически такая же, как catch в C++ - подлавливаем группу ошибок в одном месте (в данном примере это функция handle_error

Да, не совсем удобно из за неприспособленности C++ к асинхронщине.
Можно сделать по-удобнее, двумя вариантами:
1. либо написать препроцессор(например на питоне) - все зашибись, но это нестандарт.
2. либо выучить haskell (научиться на нем программировать), написать на нем обертку, потом перевести на шаблоны C++ (на шаблонах можно программировать только в чисто функциональном стиле, а чтобы это уметь - надо иметь опыт в haskell, там все куда проще и круче). - но синтаксис может получиться не совсем короткий, зато решение стандартное.

Пока мне хватает ручного handle_error. Если будут проблемы - скорее всего буду делать по второму варианту.
Go to the top of the page
 
+Quote Post
DASM
сообщение Dec 6 2017, 16:21
Сообщение #237


Гуру
******

Группа: Свой
Сообщений: 3 644
Регистрация: 28-05-05
Пользователь №: 5 493



А автор тем временем вытяснющую блокирующую в комлект включил.
Go to the top of the page
 
+Quote Post
AHTOXA
сообщение Dec 6 2017, 21:17
Сообщение #238


фанат дивана
******

Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684



Дайте, пожалуйста, ссылочку, чтобы по всей теме не искать.


--------------------
Если бы я знал, что такое электричество...
Go to the top of the page
 
+Quote Post
DASM
сообщение Dec 7 2017, 06:05
Сообщение #239


Гуру
******

Группа: Свой
Сообщений: 3 644
Регистрация: 28-05-05
Пользователь №: 5 493



https://www.state-machine.com
Go to the top of the page
 
+Quote Post
AHTOXA
сообщение Dec 7 2017, 15:29
Сообщение #240


фанат дивана
******

Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684



Благодарю.


--------------------
Если бы я знал, что такое электричество...
Go to the top of the page
 
+Quote Post

17 страниц V  « < 14 15 16 17 >
Reply to this topicStart new topic
2 чел. читают эту тему (гостей: 2, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 18th July 2025 - 14:17
Рейтинг@Mail.ru


Страница сгенерированна за 0.01511 секунд с 7
ELECTRONIX ©2004-2016