arkhipenko / TaskScheduler

Cooperative multitasking for Arduino, ESPx, STM32, nRF and other microcontrollers
http://playground.arduino.cc/Code/TaskScheduler
BSD 3-Clause "New" or "Revised" License
1.22k stars 224 forks source link

Overwriting Arduino's "delay" function? #102

Closed FrankyBoy closed 4 years ago

FrankyBoy commented 4 years ago

Hi there!

Is it possible to overwrite arduino's built-in "delay" function with the non-blocking one supplied by this library? I.e. basically doing the same as Arduino's own Scheduler does? Would be really helpful together with other libraries that just use delay() internally.

Cheers :)

arkhipenko commented 4 years ago

No. It's a completely different context. TS's delay is a delay of a single Task, while Arduino delay is a delay of the entire sketch.

FrankyBoy commented 4 years ago

As far as I can tell, delay(), if you use it in the context of a Scheduler.h thread, is supposed to yield the thread context.

PS: at least that's how I would interpret the code samples from Scheduler, otherwise using delay() would completely mess them up.

FrankyBoy commented 4 years ago

Alright, did some digging, hope I found the right code ...

Would that mean delay() actually already should yield to another thread (which would be nice)?

arkhipenko commented 4 years ago

TaskScheduler is a cooperative library. All tasks run in the same thread. There is no yield to "other" thread. You "yield" or rather just return from the callback method back to the scheduler to pass control to another task. That's the principle difference.

FrankyBoy commented 4 years ago

Arduino's scheduler is also cooperative. Otherwise you wouldn't have to yield() in the first place. I is quite literally exactly the same concept.

arkhipenko commented 4 years ago

It is quite literally exactly the same concept.

I respectfully disagree. Although in principle Scheduler does implement cooperative scheduling, the fundamental difference is that TS does not do context switching. TS actual scheduler part is small and efficient precisely because it does not maintain the task's state (registers and stack). Also the yielding part (do have a look under the hood of Scheduler!) is implemented in assembly and is very platform-dependent, while TS runs practically on anything (even Raspberry Pi - I did that!)

I see the allure of delay() - it does not require breaking up code into chunks. Unfortunately on the scheduling side, it creates too many headaches.

So here, unfortunately, I will not be overloading the delay(), and anyone is free to use Scheduler (if you are running on SAM or SAMD board). In TS you yield when you return from the task's callback.

By the way - a positive side effect of running in the same thread - you only need 1 stack, and you need to worry about 1 stack. With Scheduler (and FreeRTOS for that matter) you have to provide stack memory for every task, which is a) waste, and b) additional headache since now you need to worry about stack overruns as many times as the number of tasks you run.

And finally, the API of Scheduler is a joke. 3 methods?...

Cheers