Маленький таскер (критика)
- Войдите на сайт для отправки комментариев
Чт, 13/12/2018 - 14:03
Здравствуйте коллеги
В одной из задач понадобилось паралельное выполнение нескольких задач.
Сответвенно, изобрел свой велосипед. Ключевой особенностью велосипеда - возможность самоубийства задачи и динамическое добавление задач.
Хотел бы увидеть критику по коду в части возможных подводный камней, при использовании указателей...
class task
{
public:
task *next;
void (*func)();
uint8_t st = 1;
task(void (*f)())
{
func = f;
}
};
class taskManager
{
public:
task *current = nullptr;
task *prev = nullptr;
void add(void (*f)())
{
if (current == nullptr) //создание первого элемента
{
current = new task(f);
prev = current;
current->next = current;
}
else //создание последующих
{
task *temp = new task(f);
temp->next = current;
prev->next = temp;
}
}
void exec()
{
if (current == nullptr) return;
if (current->st == 0)
{
if (current != current->next) //удаление элемента
{
task *temp = current;
prev->next = current->next;
current = current->next;
delete temp;
}
else //удаление последнего элемента
{
delete current;
current = nullptr;
}
return;
}
current->func();
prev = current;
current = current->next;
}
void del()
{
current->st = 0;
}
};
taskManager taskManager;
void f1()
{
Serial.println("f1");
static uint8_t i;
if (i == 9) taskManager.del();
++i;
}
void f2()
{
Serial.println("f2");
static uint8_t i;
if (i == 3) taskManager.del();
++i;
}
void f3()
{
Serial.println("f3");
static uint8_t i;
if (i == 1) {
taskManager.add(f4);
taskManager.del();
}
++i;
}
void f4()
{
Serial.println("f4");
static uint8_t i;
if (i == 10) {
taskManager.del();
}
++i;
}
void setup()
{
Serial.begin(9600);
taskManager.add(f1);
taskManager.add(f2);
taskManager.add(f3);
}
void loop()
{
taskManager.exec();
delay(100);
Serial.println("step");
}
Админы, поправьте плиз втавку кода, тут на форуме 1 сообщение не редактируется....
Здравствуйте коллеги
В одной из задач понадобилось паралельное выполнение нескольких задач.
Сответвенно, изобрел свой велосипед. Ключевой особенностью велосипеда - возможность самоубийства задачи и динамическое добавление задач.
Хотел бы увидеть критику по коду в части возможных подводный камней, при использовании указателей...
class task { public: task *next; void (*func)(); uint8_t st = 1; task(void (*f)()) { func = f; } }; class taskManager { public: task *current = nullptr; task *prev = nullptr; void add(void (*f)()) { if (current == nullptr) //создание первого элемента { current = new task(f); prev = current; current->next = current; } else //создание последующих { task *temp = new task(f); temp->next = current; prev->next = temp; } } void exec() { if (current == nullptr) return; if (current->st == 0) { if (current != current->next) //удаление элемента { task *temp = current; prev->next = current->next; current = current->next; delete temp; } else //удаление последнего элемента { delete current; current = nullptr; } return; } current->func(); prev = current; current = current->next; } void del() { current->st = 0; } }; taskManager taskManager; void f1() { Serial.println("f1"); static uint8_t i; if (i == 9) taskManager.del(); ++i; } void f2() { Serial.println("f2"); static uint8_t i; if (i == 3) taskManager.del(); ++i; } void f3() { Serial.println("f3"); static uint8_t i; if (i == 1) { taskManager.add(f4); taskManager.del(); } ++i; } void f4() { Serial.println("f4"); static uint8_t i; if (i == 10) { taskManager.del(); } ++i; } void setup() { Serial.begin(9600); taskManager.add(f1); taskManager.add(f2); taskManager.add(f3); } void loop() { taskManager.exec(); delay(100); Serial.println("step"); }мне кажеца, или задачи отработают последовательно, по мере добавления? О параллельности тут речи не идёт совсем.
последовательно. по очереди с помощью связанного списка. 1 запуск метода exec - 1 задача. и так по кругу.
ну а параллельность тут причём? из #1 сообщения
последовательно. по очереди с помощью связанного списка. 1 запуск метода exec - 1 задача. и так по кругу.
а смысл? :)
обыкновенный loop() делает то же самое, только код раз в 20 короче:
void loop() { Serial.begin(9600); f1(); f2(); f3(); }вот и я про то же. :)
а смысл? :)
обыкновенный loop() делает то же самое, только код раз в 20 короче:
Только квону так не пиши...
я уж думал, что еще что новое про параллельность выполнения задач, кроме таймеров узнаю, ан нет )))
Ну, тут (в loop) список фиксированный, а у товарища динамический! Но куда это применить - мне не придумывается.
Может автор намекнёт, что за задачу решал?
Динамический - это когда в лупе по условию добавляешь, а тут вообще просто массив можно юзать и проблем будет меньше на порядок.
в данном случае паралельность расмматривалась "виртуальная". т.е. быстрое переключение между неблокирующими задачами.
идея была, используя функции со стейт-машинами реализовать различные эфекты переключения цифр светодиодной ленты (на самом деле не принципиально).
Тонкость в том, что хотелось иметь "самоубивающуюся" задачу. т.е. я по коду где-то запустил смену цвета и забыл. Задача доработала (а работать она должна некоторое время, что бы реализовать эфекты плавного затухания \ разгорания. Не блокируемость обеспечивается стейт-машиной) и самозавершалась.
Ну, тут (в loop) список фиксированный, а у товарища динамический!
он него динамический только потенциально, если в его класс добавить методы изменения порядка выполнения задач по каким-либо признакам. А так как сделано сейчас - от моего списка в ЛУП не отличается ничем :)
Ну в примере-то да, динамики никакой. Вот я поэтому про задачу и спросил - вдруг оно и правда для чего-то нужно!
идея была, используя функции со стейт-машинами реализовать различные эфекты переключения цифр светодиодной ленты (на самом деле не принципиально).
в варианте с ЛУП функции точно так же внутри могут быть стейт-машинами ровно с теми же возможностями...
Я бы сказал. что в Вашей реализации полезное зерно - только в единообразном оформлении задач как членов одного класса. А сам "таскер" в том виде, как сейчас - имхо, вещь бесполезная
Для функций действительно это можно и в лупе, только тогда дополнительно для каждой f() надо будет делать влаг запуска \ останова.
А вот если у нас вместо функции будут классы инициируемые во время работы программы, то просто в лупе это не проканает... В данном случае f() как пример, не более того.
Меня на самом деле интересует вопрос не как сделать проще (это я и сам могу), а не пропустил ли я чего нить при работе с указателями...
Проще говоря - возможна ли тут утечки памяти ?
Канешна.
Для функций действительно это можно и в лупе, только тогда дополнительно для каждой f() надо будет делать влаг запуска \ останова.
А вот если у нас вместо функции будут классы инициируемые во время работы программы, то просто в лупе это не проканает...
Чего там не проканает. Указатель на динамический обект null - нет обекта и из лупа не вызываем, не null - все путем, обект иничен вызов из лупа делаем.
Меня на самом деле интересует вопрос не как сделать проще (это я и сам могу), а не пропустил ли я чего нить при работе с указателями...
Ну как - чего?! Как всегда проверку успешности выделения памяти и реакцию на неуспешность ;)
Ну как бы так и сделано...
Ну проверку надо бы :) тока не понятно куда экстеншен кинуть... хотя...
Мошт, exeption?
Достатошно NULL вернуть.
//Мошт, exeption?
угу. Тока всеравно ж некуда.
Просто ТС путает какойта extention и exeption. Вот я и спрашываю. Мошт, он и не подозревает, што некуда, и единственная функция, которая ему поможет, это abort(), другой нету. ¦(
#167 Но здесь все реализуется через millis, а значит задачи медленого реагирования. И раз запустил - то выполнилась когда надо и самоубилась. Надо еще раз- запустите в теле задачи еще раз эту же задачу или другие по желанию.
Если в контроллере кончилось место под динамические обекты - ресет. Ну или решить что не так уж и хотелось то этот обект распределять. Помнится когда скринсейвер писал, то так и делал, нет места под очередной пузырек, безцельно блуждающий по экрану - ну и хрен с ним, нибудет его значить. Иногда так годится, жаль не часто.
Просто ТС путает какойта extention и exeption. Вот я и спрашываю. Мошт, он и не подозревает, што некуда, и единственная функция, которая ему поможет, это abort(), другой нету. ¦(
У меня в телефонной станции есть extentions... может он телефонист?
отвлекли, слово перепутал ))) и нет, не телефонист )
ИМХО В посте 167 есть неопределенное поведение после самоубийства задачи из середины списка. та компоновка, которая в примере, эту проблему не выявляет, так как фактически в пуле задач присутсвует только одна
задача...
и 2 момент. вроде как после delete указатель не становиться равным NULL, хотя вроде как должен. это я на своем коде очень хорошо понял...
roman2712@ma, я не хочу жевать эту проблему. Приводить кучу доводов и ход мысли. Потому чтомне сейчас не надо. Может потом позже напишу или скорее не напишу.