coroutines in C

Schwarz78
Offline
Зарегистрирован: 19.01.2019

Давно хотел обсудить с кем-нибудь, кому интересно, такую вещь, как protothreads, они же "coroutines in C".

https://ru.wikipedia.org/wiki/Протопотоки

http://dunkels.com/adam/pt/index.html

Я в курсе, что мнения разнятся от восторгов до "мерзкие, мерзкие макросы, фуу...".

Сразу скажу, я осмелился сделать на protothreads пару проектов, от простых к.автоматов управления питанием более умного устройства, до контроллера с Modbus-мастером, UDP и "динамическим" HTTP сервером. Это были только 51-е контроллеры. Всё успешно работает.

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Вы или крестик снимите или трусы оденьте.  С одной стороны процессор,  с другой стороны ПЛИС, а вы как гордый сокол между ними.  

Schwarz78
Offline
Зарегистрирован: 19.01.2019

Выглядит это примернр так (пример с сайта Адама Данкелса):

#include "pt.h"
 
struct pt pt;
struct timer timer;
 
PT_THREAD(example(struct pt *pt))
{
  PT_BEGIN(pt);
 
  while(1) {
    if(initiate_io()) {
      timer_start(&timer);
      PT_WAIT_UNTIL(pt,
         io_completed() ||
         timer_expired(&timer));
      read_data();
    }
  }
  PT_END(pt);
}

Полное отсутствие delay, явное отсутствие вызовов millis, явное присутствие ожидания события, но на время ожидания управление отдаётся... Кому?... Тем, кто не любит много делать в прерываниях (т.е. на "том свете"), а любит всё делать "в лоб".

И тем, кому надоели явные конечные автоматы.

Schwarz78
Offline
Зарегистрирован: 19.01.2019

Ещё раз, пожалуйста. Я слово verilog знаю конечно, но вы мне льстите, я может пару раз пальцем по ПЛИС провёл в своей жизни, но не то чтобы программировать. 51 - это такая забытая архитектура, как Тадж Махал, или пирамиды.

Трусы - надевают, замечу.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Schwarz78 пишет:

Давно хотел обсудить

Так обсуждайте! Почитаем Ваше мнение, посмотрим, может чего тоже скажем. А то пока это лишь приглашение кому-то начать обсуждение. Но идея-то Ваша, Вам и начинать.

sadman41
Онлайн
Зарегистрирован: 19.10.2016

А я вот, хоть убей, не понимаю смысла полноценной event-driven архитектуры на МК. В принципе понятно, когда система в idle state крутится - тогда, видимо, всё это красиво работает. Но при какой-то более-менее существенной нагрузке сразу встает проблема приоритерезации какого-то потока: читаем, допустим, буфер UART и тут прилетело требование обслужить входящий TCP коннект. Как тут без дополнительных наворотов придать системе способность выбрать наиболее важный процесс? Стоит ли оверхед выделки, как грицца или это просто ради челленджа на 100% использование ресурса МК (сделай, типа, как на Big PC)?

Schwarz78
Offline
Зарегистрирован: 19.01.2019

ЕвгенийП пишет:

Так обсуждайте! Почитаем Ваше мнение, посмотрим, может чего тоже скажем. А то пока это лишь приглашение кому-то начать обсуждение. Но идея-то Ваша, Вам и начинать.

Я-то давно сам с собой обсудил, иначе не стал бы использовать. Коллеги смотрели на меня с интересом и переспрашивали "прото-кто?" или "что threads?".

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

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Вот verilog  и есть ваши протопотоки. Напишите компилятор verilog в процессоры и ваша тема исчерпана.

Schwarz78
Offline
Зарегистрирован: 19.01.2019

sadman41, здесь чисто кооперативная многозадачность. Точнее здесь нет никакой многозадачности. По сути - это конечный автомат, но программист пишет как будто кооператив. В этом и прелесть. А как реализовано. Почитайте вот, откуда ноги выросли:

https://ru.wikipedia.org/wiki/Устройство_Даффа

Мне нравятся такие изящные фиговины, например.

Schwarz78
Offline
Зарегистрирован: 19.01.2019

qwone пишет:

Вот verilog  и есть ваши протопотоки. Напишите компилятор verilog в процессоры и ваша тема исчерпана.

Чем больше вы мне пишете - тем меньше я вас понимаю.

sadman41
Онлайн
Зарегистрирован: 19.10.2016

Нет, ну если просто нравятся изящные фиговины, то тут и обсуждать нечего. Кому-то нравится водка, кому-то пиво. И никакого консенсуса тут не будет. А вот собутыльников найти можно, теоретически.

Schwarz78
Offline
Зарегистрирован: 19.01.2019

sadman41 пишет:

Нет, ну если просто нравятся изящные фиговины, то тут и обсуждать нечего. Кому-то нравится водка, кому-то пиво. И никакого консенсуса тут не будет. А вот собутыльников найти можно, теоретически.

Терпеть не могу "изящных фиговин". Я не так выразился. Мне нравятся красивые решения некрасивых задач. Под "некрасивыми решениями" я понимаю конечные автоматы вида switch-case или ни дай бог if-else-if.

Если вы писали код под RTOS - вы поймёте о чём я. Здесь вам предлагается удобство кооперативной ОС без накладных расходов операционной системы. Здесь нет планировщика. Но здесь есть:

- передача управления (yeld),

- неблокирующее ожидание события (wait), 

и ещё пара плюшек.

 

sadman41
Онлайн
Зарегистрирован: 19.10.2016

Schwarz78 пишет:

Полное отсутствие delay, явное отсутствие вызовов millis, явное присутствие ожидания события, но на время ожидания управление отдаётся... Кому?... Тем, кто не любит много делать в прерываниях (т.е. на "том свете"), а любит всё делать "в лоб".

Думаю, что дело пойдет лучше, если Вы предложите не код прототипа, а что-то более приземленное и более связанное с ардуинством. Чтение показаний с сенсоров, реакцию на эти показания... всё это в раскладе для протопотоков этих.

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Schwarz78 пишет:
Чем больше вы мне пишете - тем меньше я вас понимаю.
 

Видео:Я даже воздухом не дышу  https://www.youtube.com/watch?v=7TsQLGimB2I 

Все на чем люди пишут это языки высокого уровня. А вот то что уже заливается в камни ну очень далеко от оригинала. Особенно это ясно в ПЛИСах. Ну сложно набить большую таблицу. Вот и создают "многозадачные модули" и потом собирают из них "программу". Вы тоже подобное предложили в этой теме. А дальше просто написать компилятор и вуаля самая быстрая программа в итоге. Но Си все же не подходит для этого. Граната не той системы.

Schwarz78
Offline
Зарегистрирован: 19.01.2019

Да, думаю вы правы. Blink, например. Плохой из меня коммивояжёр)

Schwarz78
Offline
Зарегистрирован: 19.01.2019

qwone пишет:

Schwarz78 пишет:
Чем больше вы мне пишете - тем меньше я вас понимаю.
 

Видео:Я даже воздухом не дышу  https://www.youtube.com/watch?v=7TsQLGimB2I 

Все на чем люди пишут это языки высокого уровня. А вот то что уже заливается в камни ну очень далеко от оригинала. Особенно это ясно в ПЛИСах. Ну сложно набить большую таблицу. Вот и создают "многозадачные модули" и потом собирают из них "программу". Вы тоже подобное предложили в этой теме. А дальше просто написать компилятор и вуаля самая быстрая программа в итоге. Но Си все же не подходит для этого. Граната не той системы.

Мы с вами точно в тех плоскостях, которые не пересекаются.

sadman41
Онлайн
Зарегистрирован: 19.10.2016

Schwarz78 пишет:

Да, думаю вы правы. Blink, например. Плохой из меня коммивояжёр)

Ради блинка потоки заводить... Нет, я, конечно могу себе представить, что в одном потоке идет отрисовка на дисплей, во втором чтение далласа, в третьем - bmp какого-нибудь. Но я, если честно, не совсем понимаю - в чем будет выигрыш против простого разноса по функциям и вызова их по-очереди в лупе.

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

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

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

sadman41 пишет:

[ Однако там всё рулится "само" - на уровне OS. Там главное отфоркнуться правильно, а дальше уже как и в однопоточном приложении работаешь.

Ну так оно и есть. Или создавать ОS для поддержки этих потоков. Или компилятор "переосысливает" концепцию программы программиста и рисует оптимальный код под конкретный исходник. 

Schwarz78
Offline
Зарегистрирован: 19.01.2019

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

#include "pt.h"

static struct pt _blink13_pt;
static struct pt _blink1_pt;
static struct pt _serial_pt;

static PT_THREAD(_blink13(struct pt *pt))
{
static uint32_t time_stamp = millis();
  PT_BEGIN(pt);
  while(1)
  {
    PT_WAIT_UNTIL(pt, millis()-time_stamp > 50);
    time_stamp = millis();
    digitalWrite(13, LOW);
    PT_WAIT_UNTIL(pt, millis()-time_stamp > 950);
    time_stamp = millis();
    digitalWrite(13, HIGH);
  }
  PT_END(pt);
}

static PT_THREAD(_blink1(struct pt *pt))
{
static uint32_t time_stamp = millis();
  PT_BEGIN(pt);
  while(1)
  {
    PT_WAIT_UNTIL(pt, millis()-time_stamp > 50);
    time_stamp = millis();
    digitalWrite(1, HIGH);
    PT_WAIT_UNTIL(pt, millis()-time_stamp > 3950);
    time_stamp = millis();
    digitalWrite(1, LOW);
  }
  PT_END(pt);
}

static PT_THREAD(_serial(struct pt *pt))
{
static uint32_t time_stamp = millis();
  PT_BEGIN(pt);
  while(1)
  {
    PT_WAIT_UNTIL(pt, millis()-time_stamp > 10000);
    time_stamp = millis();
    Serial.print(F("Hi, man, millis = "));
    Serial.println(time_stamp);
  }
  PT_END(pt);
}

void setup()
{
  PT_INIT(&_blink13_pt);
  PT_INIT(&_blink1_pt);
  PT_INIT(&_serial_pt);
  pinMode(13, OUTPUT);     
  pinMode(1, OUTPUT);     
  digitalWrite(13, LOW);
  digitalWrite(1, HIGH);  // пин RXD зажигается инверсно пину D13
//  Serial.begin(9600);   // поскольку D1 это пин RXD, оне конфликтуют, но не смертельно
}

void loop()
{
  _blink13(&_blink13_pt);
  _blink1(&_blink1_pt);
//  _serial(&_serial_pt);
}

Заголовочные файлы, если захочется проверить, лежат тут (распаковать в папку со скетчем lc.h, lc-switch.h, pt.h):

http://dunkels.com/adam/download/pt-1.4.tar.gz

 

Да, если подождать немного, то можно увидеть, что светодиоды рассинхронизируются, т.е. совсем всё независимо)

sadman41
Онлайн
Зарегистрирован: 19.10.2016

Скомпилил, глянул в build preproc. Сильно вникнуть не пытался, но да, действительно - похоже на скрытый за макросами псевдодиспетчер на свичах. Пока чувства смешанные. С одной стороны - весело оформить код так, чтобы никто нихрена не понял, а с другой - в итоге по коду раскиданы те же самые свичи/миллисы, только еще придется через полгода почесать репу чтобы вспомнить на кой ты так накрутил. Ну и, конечно, полномасштабное использование глобалов для взаимодействия тредов - краеугольный камень всей этой каши из топора. Боюсь, что в сколько-нибудь большом прожекте это осложнит жись, а вовсе не облегчит.

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

Такое вобщем... нишевое решение, на первый взгляд.

b707
Онлайн
Зарегистрирован: 26.05.2017

И скока размер получился для нано?

sadman41
Онлайн
Зарегистрирован: 19.10.2016
Sketch uses 1444 bytes (4%) of program storage space. Maximum is 32256 bytes.
Global variables use 39 bytes (1%) of dynamic memory, leaving 2009 bytes for local variables. Maximum is 2048 bytes.
-------
Но у меня давно складывается такое чувство, что в последних версиях IDE вывод линковщика не всегда отражает действительность по RAM. Иногда старые скетчи свои компилю (где переменные заводятся внутри функций) и по памяти получаю результат какбутто она вообще не используется. А вот если глобалы использовать - всё по-честному. Поэтому на итоговый отчет смотрю критически.
b707
Онлайн
Зарегистрирован: 26.05.2017

sadman41 пишет:

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

так оно же само и говорит - что только Глобалы учитывает:

Global variables use 

Но я согласен, что это совсем не то, что хотелось бы видеть. Ипользует библиотека внутри класса буфер на 1кбайт - а ты и знать не будешь.

 

sadman41
Онлайн
Зарегистрирован: 19.10.2016

Ну, это да. Однако что-то мне визуально помнится, что корректней считалось )) Мож приснилось.

Вот, к слову, близкий по духу блинкер (индусский код по примеру того, что сгенерировался в preproc):

void setup()
{
  uint32_t time_stamp1, time_stamp13;
  uint8_t state1, state13;
  state1 = state13 = 0;
  time_stamp1 = time_stamp13 = millis();

  pinMode(13, OUTPUT);
  pinMode(1, OUTPUT);
  digitalWrite(13, LOW);
  digitalWrite(1, HIGH);

  while (1) {
    if (!state1 && millis() - time_stamp1 > 1000) {
      time_stamp1 = millis();
      state1 = 1;
      digitalWrite(1, LOW);
    }
    if (state1 && millis() - time_stamp1 > 1000) {
      time_stamp1 = millis();
      state1 = 0;
      digitalWrite(1, HIGH);
    }
    if (!state13 && millis() - time_stamp13 > 250) {
      time_stamp13 = millis();
      state13 = 1;
      digitalWrite(13, LOW);
    }
    if (state13 && millis() - time_stamp13 > 250) {
      time_stamp13 = millis();
      state13 = 0;
      digitalWrite(13, HIGH);
    }
  }
}


void loop() {}
----------------------
Sketch uses 982 bytes (3%) of program storage space. Maximum is 32256 bytes.
Global variables use 9 bytes (0%) of dynamic memory, leaving 2039 bytes for local variables. Maximum is 2048 bytes.
----------------------
 
Так что пока даже и не знаю - хорош ли этот тредогенератор... стоит ли изводить на него ресурс МК...
 
b707
Онлайн
Зарегистрирован: 26.05.2017

sadman41 пишет:

 
Так что пока даже и не знаю - хорош ли этот тредогенератор... стоит ли изводить на него ресурс МК...
 

В принципе, накладные не так и велики. Если конечно, они не будут расти пропорционально коду.

Например, для RTOS пишут, что накладные расходы на Уно-Нано "всего" порядка 2к. Но они отжираются сразу и почти не зависят от пользовательского кода, насколько я знаю.

sadman41
Онлайн
Зарегистрирован: 19.10.2016

b707 пишет:

sadman41 пишет:

Так что пока даже и не знаю - хорош ли этот тредогенератор... стоит ли изводить на него ресурс МК...

В принципе, накладные не так и велики. Если конечно, они не будут расти пропорционально коду.

Да, но и явного преимущества в этой технологии пока что не видно. Внутре те же самые свичи-миллисы.

b707 пишет:

Например, для RTOS пишут, что накладные расходы на Уно-Нано "всего" порядка 2к. Но они отжираются сразу и почти не зависят от пользовательского кода, насколько я знаю.

А чего потом делать с этой RTOS, если она всю память сожрет сразу? Вот мне нужен буфер для sprintf(), к примеру - откедова под него память получить?

 

sadman41
Онлайн
Зарегистрирован: 19.10.2016

Небольшая корректировка. Я же код Шварца с сериалом откомпилил, а свой без него. Сообразил, пока бродил к чайнику...

Итого, с прототредами:

Sketch uses 1278 bytes (3%) of program storage space. Maximum is 32256 bytes.
Global variables use 37 bytes (1%) of dynamic memory, leaving 2011 bytes for local variables. Maximum is 2048 bytes.
 
С if()-ами
 
Sketch uses 982 bytes (3%) of program storage space. Maximum is 32256 bytes.
Global variables use 9 bytes (0%) of dynamic memory, leaving 2039 bytes for local variables. Maximum is 2048 bytes.

Расчет RAM на совести линкера.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Для всяких далласов и прочих "долгих ожиданийЭ, мне гораздо больше нравится подход T++. Там отложенные значения естественны и предельно просты. 

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

Schwarz78
Offline
Зарегистрирован: 19.01.2019

sadman41 пишет:

Вот, к слову, близкий по духу блинкер (индусский код по примеру того, что сгенерировался в preproc):

Так что пока даже и не знаю - хорош ли этот тредогенератор... стоит ли изводить на него ресурс МК...
 
Этот блинкер не очень-то близкий по духу, если честно. Тут любое дополнительное действие надо пихать в очередной if(). Когда код разрастётся - это будет нечитаемо уже. Представьте несколько таймеров, клавиатура, дисплей, последовательный порт. Тот же UART, например у вас мастер, и вам надо опрашивать штук 10-20 slave. Создаёте цикл из числа слэйвов и в каждой итерации создаёте запрос, отправляете, дальше WAIT ответа или тайм-аута, дальше разбор ответа. Это всё очень долго, а остальные части программы тоже должны работать. Обычно это делается автоматом на switch-case, так вот такая запись мне понятна и спустя 3 года, а на switch-case приходится долго разбираться в последовательности состояний.
sadman41
Онлайн
Зарегистрирован: 19.10.2016

Вот-вот, вопрос в крови. Если для чтения далласа "без задержек" надо будет еще восемь страниц крепко заваренного на зубодробительной теории кода накидать, то среднестатистическая "ардуинная" задача превратится в неподъемный камень для целевой аудитории. Конечно есть люди, которые на двадцати разновидностях ассемблера пять лет будут полировать "погодную станцию" и выберут наилучший вариант в итоге, но таких тут единицы. Для большинства местных задачек и delay(1000), вобщем-то, не помеха - прямо скажем )) А уж "блинк без дилэй" закрывает 90% вопросов.

sadman41
Онлайн
Зарегистрирован: 19.10.2016

Schwarz78 пишет:

Этот блинкер не очень-то близкий по духу, если честно. Тут любое дополнительное действие надо пихать в очередной if(). Когда код разрастётся - это будет нечитаемо уже. Представьте несколько таймеров, клавиатура, дисплей, последовательный порт. Тот же UART, например у вас мастер, и вам надо опрашивать штук 10-20 slave. 

А ежели мы в него рельсу сунем, да? Как будто кто-то сомневается, что можно придумать условия, в которых одно решение будет превосходным, а другое - отвратным. Вы написали блинкер, который мыргает и я написал такой же. Чем они далеки друг от друга?

А в том, что разросшийся код со временем поглощает мозг своего создателя без остатка - у меня и сомнений нет. Хоть на if() он сделан, хоть на goto, хоть на тредах. Я же не пишу, что ваши прототреды отвратны. Да, как синтаксический сахар для людей, которым нравятся такие приемы и досконально понимающих, как развернутся данные макросы  - они отличны. Конечно можно поиметь проблемы со вложенными в тред своими свичами, помучаться с глобалами и пр. Несомненно, что потр... атив определенное время и усилия на освоение бензопилы, можно ею создавать офигенные скульптуры. Но, повторюсь, что на мой взгляд это удел единиц, у которых этого времени в избытке или вот так сложилось, что мозг заточен под художества. 

Schwarz78
Offline
Зарегистрирован: 19.01.2019

sadman41 пишет:

Вы написали блинкер, который мыргает и я написал такой же. Чем они далеки друг от друга?

...

Конечно можно поиметь проблемы со вложенными в тред своими свичами, помучаться с глобалами и пр. 

Мой легко читается, и можно добавлять "потоки" относительно безболезненно. Он не выглядит "индусским".

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

Глобальные переменные - да, неприятно, но в С без них вообще сложно обойтись.

sadman41
Онлайн
Зарегистрирован: 19.10.2016

Дак мы щас квона попросим - он класс накидает и можно эти мигалки тоже безболезненно размножать ))

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

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

Schwarz78 пишет:

Глобальные переменные - да, неприятно, но в С без них вообще сложно обойтись.

Да ну?? ;))

Schwarz78
Offline
Зарегистрирован: 19.01.2019

sadman41 пишет:

Дак мы щас квона попросим - он класс накидает и можно эти мигалки тоже безболезненно размножать ))

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

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

Я к ардуино так же отношусь примерно, вот и подумал, что этот форум - самое место обсуждать подобные неоднозначные подходы.

Schwarz78
Offline
Зарегистрирован: 19.01.2019

wdrakula пишет:

Да ну?? ;))

Ну да) Как из прерывание что-нибудь достать без глобальных? Мы же про С говорим?

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

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

Раньше было ясно, октуда ноги растут - новички приходили из Веб и жить не могли без объектного мышления и параллельный тредов.

Но тут новый человек говорит, что сам из эмбеддинга пришел и контроллеры на завтрак в тостере готовит, но что мы видим: опять треды!

Это не наезд, не принимай на свой счет, просто подшучиваю!

Мы, понимаешь, "...давно тут сидим" (с), видали много разных людей. Так вот есть две "полезности" в любой технологии програмирования:

1. Полезность для программистов - сокращение времени разработки, уменьшение вероятности ошибки, оптимизация кода;

2. Полезность для новичка - когда новичек, увидив новую для себя технологию, закричит: "Так вот из чего, на самом деле, тетька сделана!" и станет задавать меньше тупых вопросов на форуме.

-----

Полезностью для программиста разные технологии псевдотредов обладают лишь с точки зрения расширения эрудиции. Большинство тут - дядьки около 50 с такой эрудицией, что если ее расширить, она лопнет. Разрабатывать код, ограничивая себя одним инструментом - неудобно. Где-то в коде автоматная часть, где-то псевдопараллельная, где-то очередь, а где-то вообще делей() стоит!

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

---------

Про эти конкретные псевдотреды - ничем не хуже других, вполне мило. Взял бы себе на вооружение? - ни за что! ;)) Просто потому, что для двух-трех потоков не нужно, а код с бОльшим количеством псевдопараллельных потоков, на мой взгляд, требует перепроектирования.

Где нужно? Разработка на скорость - например "на заказ". Думать о слиянии потоков и правильном проектировании кода - нет времени, если хватает ресурсов - быстро накидать решение, прогнать пару тестов и отдать заказчику.

Чё-тут-думать? ;)) - поток на кнопки, поток на экран, поток на сенсоры, поток на актуаторы. Вот и принцип ЛЮБОЙ программы для контроллера. Если есть Веб и сеть, то еще поток на Веб и поток на SMS-GSM. (это был сарказм)

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

Schwarz78 пишет:

wdrakula пишет:

Да ну?? ;))

Ну да) Как из прерывание что-нибудь достать без глобальных? Мы же про С говорим?

А писать интерфейсы начали только в С++? Или что-то мешает из прерывания дернуть функцию со статическими переменными? Вопрос желания.

sadman41
Онлайн
Зарегистрирован: 19.10.2016

Если не думать о правильном проектировании, то в итоге можно актуатором по лбу получить )) Расслабишься с этими тредами, потеряешь видение целостной картины таймлайна и приехали - всё какбутто красиво в каждом треде и научно правильно - с yeld-ами, но отчего-то на "одноядерном" контроллере с круговым переключением тредов не попадаешь сразу в нужный, а пропускаешь вперед себя кого-то, а у него там свои дела и твой йелд превращается в неопределённую бесконечность ))

Schwarz78
Offline
Зарегистрирован: 19.01.2019

Всё вы правильно пишете, господа, конечно это всё от скуки и однообразия. Периодически хочется что-то ещё попробовать.

wdrakula пишет:

А писать интерфейсы начали только в С++?

Опять я что-то пропустил? А можно ссылку, где почитать про это?

sadman41 пишет:

Если не думать о правильном проектировании

то в любом случае по лбу сработает.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Schwarz78 пишет:

Периодически хочется что-то ещё попробовать.

Вот и попробуйте Т++. Ссылку я выше давал.

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

Schwarz78 пишет:

wdrakula пишет:

А писать интерфейсы начали только в С++?

Опять я что-то пропустил? А можно ссылку, где почитать про это?

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

Ничего не мешает спрятать переменную (массив, структуру) в статик переменных функции и обращаться к ней геттерами и сеттерами, как самый примитивный интерфейс. Так и любые идеи интерфеса: "печатаемый", "открываемый", и все, что в голову придет. Пишешь универсальную интерфейсную функцию, которой передается параметр и некие особенности текущего объекта, потом, если "чистый Си", то макросом или обёрткой переназываешь, скрывая лишние параметры.

Просто в ООП языках больше выразительных средств, для написания подобного. И читать код легче.

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

ЕвгенийП пишет:

Schwarz78 пишет:

Периодически хочется что-то ещё попробовать.

Вот и попробуйте Т++. Ссылку я выше давал.

Женя. Вот ты - "язычник", а ты представляешь или, возможно, обсуждал и знаешь, КАК конструкции Т++ реализовывать?

Я ж немного компиляторщик был в юности... это, по мне, почти полный П! Вот это "неготовое" значение порождает не результат, а код, который надо или пометить или положить в стек, поставить семафоры... гимор на гиморе, не даром первые реализации были полным г...!

То есть писать программисту - удобно, решать компьютеру... блин! Он же перегреется! ;)))

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

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

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

Идея-то на самом деле растёт из теории "частичных вычислений", там порылись ребята из ИПМ (может знаешь) - Андрей Климов, Лёша Лацис и вообще их семнар (т.н. "рефал-компания", там ещё Сергей Абрамов). Чья персонально идея была - не помню.

Schwarz78
Offline
Зарегистрирован: 19.01.2019

wdrakula пишет:

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

Ничего не мешает спрятать переменную (массив, структуру) в статик переменных функции и обращаться к ней геттерами и сеттерами, как самый примитивный интерфейс. Так и любые идеи интерфеса: "печатаемый", "открываемый", и все, что в голову придет. Пишешь универсальную интерфейсную функцию, которой передается параметр и некие особенности текущего объекта, потом, если "чистый Си", то макросом или обёрткой переназываешь, скрывая лишние параметры.

Просто в ООП языках больше выразительных средств, для написания подобного. И читать код легче.

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

PS Хотя нет, вопрос глупый. Делать то же, что и всегда - атомизировать доступ к критичным участкам.

Schwarz78
Offline
Зарегистрирован: 19.01.2019

ЕвгенийП пишет:

Вот и попробуйте Т++. Ссылку я выше давал.

Я только в С++ начал врубаться (точнее в ООП), а вы мне Т++ уже советуете. Я сходил, конечно, туда. Прочитал два раза, понял что не понял, и ушёл.

Schwarz78
Offline
Зарегистрирован: 19.01.2019

Кстати, я тут вспомнил, что у нас gcc, а у него есть address labels. Вот для этого случая в исходном архиве есть файл lc-addrlabels.h, который если использовать вместо lc-switch.h даст возможность пользовать switch-case внутри протопотоков в полном объёме. Правда накладные расходы возрастут с 2-х байт на поток до 4-х.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Schwarz78 пишет:

у него есть address labels

О! Настоящие мужчины подтянулись!

Schwarz78
Offline
Зарегистрирован: 19.01.2019

зачем нам рыба, раз есть икра?

Schwarz78
Offline
Зарегистрирован: 19.01.2019

wdrakula пишет:

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

Ничего не мешает спрятать переменную (массив, структуру) в статик переменных функции и обращаться к ней геттерами и сеттерами, как самый примитивный интерфейс. Так и любые идеи интерфеса: "печатаемый", "открываемый", и все, что в голову придет. Пишешь универсальную интерфейсную функцию, которой передается параметр и некие особенности текущего объекта, потом, если "чистый Си", то макросом или обёрткой переназываешь, скрывая лишние параметры.

Просто в ООП языках больше выразительных средств, для написания подобного. И читать код легче.

Посидел, почитал на эту тему, много думал, много искал, опять много думал. Есть даже целая книга http://www.planetpdf.com/codecuts/pdfs/ooc.pdf.

Ну вот глядя на это вот всё, применительно к контроллерам, пытаться заниматься инкапсуляцией (ни дай бог полиморфизмом и наследованием) на чистом Си - это ООП-дрочерство в чистом виде. У меня слёзы кровавые наворачиваются, когда я вижу такой изврат. Хотя надо понимать, это придумали ещё до С++, не от хорошей жизни. Поэтому, если я буду писать на С - буду писать в духе этого языка, а смогу думать на С++, а там возможности видятся большие - если мой код станет таким же по размеру или меньше, чем на С - тогда я и скажу, что три кита ООП + умный компилятор + умный программист = лучше ламера на ассемблерном фортране.