EmbeddedRelated.com
Forums

Common name for a "Task Loop"

Started by Tim Wescott June 24, 2016
On Tue, 28 Jun 2016 06:20:43 +0300, Dimiter_Popoff wrote:

> On 28.6.2016 г. 05:54, Simon Clubley wrote: >> > > ..... >> I still think that's a polling loop because you are reaching out to the >> sensor and asking it for it's current value. > > "Polling" in programming means "as opposed to interrupt handling". > How is this opposed to "interrupt handling". > > What you suggest to be polling is simply a loop of calls to subroutines. > A "call loop" is what describes it - although it does not matter a lot > what word is used as long as it is not an already widely accepted one > like "polling" which you want to redefine. Nothing wrong with that of > course - as long as you don't have to communicate with other people > using your redefined term. > > So much talk about so little :-). Although Tim's topic idea worked, > produced quite a discussion.
Well, I was hoping for a name of a design pattern, and I'm still not happy about my choices. So from that perspective it's a wash. "Super loop" seems closest, but it seems to more capture the notion of _always_ executing A, B, C, rather than executing only those bits that are ready. -- Tim Wescott Control systems, embedded software and circuit design I'm looking for work! See my website if you're interested http://www.wescottdesign.com
On Mon, 27 Jun 2016 08:33:14 +0100, FreeRTOS info wrote:

> On 24/06/2016 19:37, Tim Wescott wrote: >> So, this is the third time in a month or so that I've needed to tell >> someone "use a task loop" -- but I'm not sure if I can say "just Google >> it". >> >> So: When I say "task loop" I mean that I'm _not_ using an RTOS, but >> rather that I'm doing some small thing in a small processor, and >> somewhere in my code there's a loop that goes: >> >> for (;;) >> { >> if (task_1_ready) >> { >> task_1_update(); >> } >> else if (task_2_ready) >> { >> task_2_update(); >> } >> else if (task_3_ready) >> // et cetera >> } >> >> The "task_n_ready" variables are set offstage (in an ISR, or by one of >> the task_n_update functions) and reset within the tasks. >> >> So -- is there a common Google-able term for this? >> >> > Assuming a single thread, I would just call this a 'super loop', and, to > the best of my knowledge, believe that is the common way of describing > it. A quick google for '"super loop" software' brings the following: > > http://uhaweb.hartford.edu/kmhill/suppnotes/SuperLoop/SuperLoopC.v1.htm > https://en.wikibooks.org/wiki/Embedded_Systems/Super_Loop_Architecture > > which I think is inline with your structure.
I guess I'm going to have to be happy with "Superloop". It doesn't seem to capture the more-disciplined nature of what I was expressing, which basically implements a cooperative multitasking scheduler. Mostly I need something to point to when some newbie on a forum is looking for an alternative to doing most of their processing in ISRs, because they can't imagine the "set a flag and do it later" notion. -- Tim Wescott Control systems, embedded software and circuit design I'm looking for work! See my website if you're interested http://www.wescottdesign.com
> I guess I'm going to have to be happy with "Superloop". It doesn't seem > to capture the more-disciplined nature of what I was expressing, which > basically implements a cooperative multitasking scheduler. >
Tim, the "Superloop" is quite ok as a term. I'm using "main loop" by myself - I don't know why exactly, maybe because it resides in main() ? :D - and because the "super" in superloop seems to me too strong. What's so "super" about it? However, you use "task" for a finite state machine. The "cooperative" thing has nothing to do with your code, basically because there aren't "tasks". "Cooperative" term is used on real multi-tasking systems in opposition to "preemtive". But I think you know very well that. For me a "task" is a code that has (or can have) an infinite loop inside, and usually doesn't return. A cooperative multitasking system is exactly like a preemtive one, but just without the preemtion. The only way to give control to other tasks is with some yield() routine. The scheduler is simpler than for a preemtive system, but it is no way close to what you are describing in your example.
On Tue, 28 Jun 2016 09:40:42 -0500, Tim Wescott wrote:

> "Super loop" seems closest, but it seems to more capture the notion of > _always_ executing A, B, C, rather than executing only those bits that > are ready.
I had called it a Round-Robin Loop, but nobody understands me because everybody calls it something else.
marți, 28 iunie 2016, 18:38:26 UTC+3, Mel Wilson a scris:
> On Tue, 28 Jun 2016 09:40:42 -0500, Tim Wescott wrote: > > > "Super loop" seems closest, but it seems to more capture the notion of > > _always_ executing A, B, C, rather than executing only those bits that > > are ready. > > I had called it a Round-Robin Loop, but nobody understands me because > everybody calls it something else.
Arduino calls it simply "loop()" :-)
Tim Wescott wrote:

> On Tue, 28 Jun 2016 06:20:43 +0300, Dimiter_Popoff wrote: > >> On 28.6.2016 �. 05:54, Simon Clubley wrote: >>> >> > ..... >>> I still think that's a polling loop because you are reaching out to the >>> sensor and asking it for it's current value. >> >> "Polling" in programming means "as opposed to interrupt handling". >> How is this opposed to "interrupt handling". >> >> What you suggest to be polling is simply a loop of calls to subroutines. >> A "call loop" is what describes it - although it does not matter a lot >> what word is used as long as it is not an already widely accepted one >> like "polling" which you want to redefine. Nothing wrong with that of >> course - as long as you don't have to communicate with other people >> using your redefined term. >> >> So much talk about so little :-). Although Tim's topic idea worked, >> produced quite a discussion. > > Well, I was hoping for a name of a design pattern, and I'm still not > happy about my choices. So from that perspective it's a wash. > > "Super loop" seems closest, but it seems to more capture the notion of > _always_ executing A, B, C, rather than executing only those bits that > are ready. >
Which is how I usually implement it, but the first thing in A is switch (state) { case IDLE: if (!input_ready) break; The tasks usually wind up having to be state machines anyhow; why bother pulling one transition out to a different place? -- Rob Gaddi, Highland Technology -- www.highlandtechnology.com Email address domain is currently out of order. See above to fix.
On 6/27/2016 7:54 PM, Simon Clubley wrote:
> On 2016-06-27, Don Y <blockedofcourse@foo.invalid> wrote: >> >> The example: >> while (FOREVER) { >> V=readADC(); >> writeDAC(V); >> } >> you termed as "polling" -- despite the fact that there are no >> visible conditionals. (I don't consider the hardwired while() >> to be a conditional -- it could be implemented with a goto.) >> > > It is an interesting example. I still think that's a polling loop > because you are reaching out to the sensor and asking it for it's > current value. > > It's possible to have polling loops in which there is no conditional > logic, but instead a pure mathematical transformation of an input > to an output is performed. While there's no obvious maths going on > in the above loop, you are still driving a second device based on > the current value of the first device.
OK. Here's pseudo-code for something I wrote many years ago to "crack" Moore machines: main() init() while (not_done) { state = get_current_state() stimulus = get_stimulus(state) put_stimulus(stimulus) update_display() } } I.e., this is indistinguishable from just "a looping algorithm". get_current_state() "reaches out to the sensor" -- in this case, the hardware implementing the FSM -- "and asks it for it's current value". For some devices, this is just a memory/IO "read". For others, it might require massaging some hardware to extract the contents of a "buried" state register, etc. (e.g. jtag interface). [Likewise, put_stimulus() may be a simple "write" or a lengthy "process (jtag) to introduce the chosen stimulus to the FSM] Of course, get_stimulus() is the meat-and-potatoes of the algorithm... Now, imagine I make the "FSM interfaces" interface to a *model* of a FSM! There's no IO involved. No "sensors". Just "data" driven by an "isolated" algorithm that is pretending to be a piece of hardware. Is this still "polling"? Or, something else -- because it is not interfacing with "sensors"? Even sensors who can be accessed unconditionally in the same way that the outputs of a simulator could? I.e., I could rewrite the Fibonacci example as a task interfacing to a "Fibonacci simulator". *Or*, a hardware device that was a "Fibonacci generator"! It's the same application -- that can be implemented with virtually identical code (see my FSM example, above). Yet, you arbitrarily call it different things?
>> So far, your distinguishing criteria is "if interrupts are used, >> then interrupt driven; else polling (even if no conditional logic >> involved)" ?? > > To me, it's more like if you have to reach out to the sensors and ask > them what their current status is, then it's polling. If you don't do > anything until the sensor tells you via some mechanism that there's > been a change in the sensor then to me it's an interrupt architecture.
What if the "some mechanism" doesn't actually tell you that there has been a change? Merely that "its time for you to look at it again"? What if that mechanism is unrelated to any particular hardware (i.e., NOT sourced by an interrupt but, rather, 10,000 iterations around the main loop? (i.e., this activity has a relative weight of 1:10,000 while some other activity might have a relative weight of 1:5,000 or 1:1,000,000)
On 6/27/2016 8:20 PM, Dimiter_Popoff wrote:
> On 28.6.2016 &#1075;. 05:54, Simon Clubley wrote: >> > > ..... >> I still think that's a polling loop >> because you are reaching out to the sensor and asking it for it's >> current value. > > "Polling" in programming means "as opposed to interrupt handling".
I see "polling" as different from "event driven". I *don't* see event driven as requiring an interrupt (foreground) system! I.e., why can't an "event" be totally synthetic: 10,000 iterations of the "big loop"? (before folks *dedicated* timer hardware to implementations, you could still "write code" :> ) Or, why can't an "event" be created by POLLING something? A piece of hardware *or* the results of some other "task"? E.g., the "line frequency clock" I described elsewhere just *looks* to see if a "zero crossing" has been detected on the AC mains "since the last time I looked" (the time between "peeks" being highly variable as it depends on how long it took to "go around the loop" on this most recent iteration. This "event" feeds an algorithm that effectively says: if (LFC_event) { signal_power_available() } else { missed_events++ if (missed_events > THRESHOLD) { signal_power_fail() } } [though it does this by way of a small state machine instead of the spaghetti code above -- you don't want to "signal" power as being available (or failed) if it already has been signaled as such; that generates superfluous "conditions" instead of "events"]
> How is this opposed to "interrupt handling". > > What you suggest to be polling is simply a loop of calls to subroutines. > A "call loop" is what describes it - although it does not matter a lot > what word is used as long as it is not an already widely accepted one > like "polling" which you want to redefine. Nothing wrong with that > of course - as long as you don't have to communicate with > other people using your redefined term.
IME, most people have their own private lexicons -- yet seem to think theirs is "universally accepted" and/or "correct". This is why I spend so much time writing "tutorials": "Hey, believe what you want. But, *these* are the definitions that *I* use and this is why they make sense..."
> So much talk about so little :-). Although Tim's topic idea worked, > produced quite a discussion.
Rob Gaddi wrote:
> Tim Wescott wrote: > >> On Tue, 28 Jun 2016 06:20:43 +0300, Dimiter_Popoff wrote: >> >>> On 28.6.2016 &#4294967295;. 05:54, Simon Clubley wrote: >>>> >>> > ..... >>>> I still think that's a polling loop because you are reaching out to the >>>> sensor and asking it for it's current value. >>> >>> "Polling" in programming means "as opposed to interrupt handling". >>> How is this opposed to "interrupt handling". >>> >>> What you suggest to be polling is simply a loop of calls to subroutines. >>> A "call loop" is what describes it - although it does not matter a lot >>> what word is used as long as it is not an already widely accepted one >>> like "polling" which you want to redefine. Nothing wrong with that of >>> course - as long as you don't have to communicate with other people >>> using your redefined term. >>> >>> So much talk about so little :-). Although Tim's topic idea worked, >>> produced quite a discussion. >> >> Well, I was hoping for a name of a design pattern, and I'm still not >> happy about my choices. So from that perspective it's a wash. >> >> "Super loop" seems closest, but it seems to more capture the notion of >> _always_ executing A, B, C, rather than executing only those bits that >> are ready. >> > > Which is how I usually implement it, but the first thing in A is > > switch (state) { > case IDLE: > if (!input_ready) break; > > The tasks usually wind up having to be state machines anyhow; why bother > pulling one transition out to a different place? >
Agreed. -- Les Cargill
On 6/28/2016 9:49 AM, Rob Gaddi wrote:
> Which is how I usually implement it, but the first thing in A is > > switch (state) { > case IDLE: > if (!input_ready) break; > > The tasks usually wind up having to be state machines anyhow; why bother > pulling one transition out to a different place?
Does each invocation of "A" have to begin at the switch? I.e., do you implement "substates" so you can resume at a different point *in* "IDLE" on the next invocation? switch (state) { case IDLE: if (!ready) break; input = get_input(); // potentially time consuming or, perhaps, // even requires a separate process to *do* // the actual "getting" -- like clocking // an SPI, etc. that takes far too much time // to tie up the "big loop" yield(); resume: if (input ...) { do_something() // transition routine for IDLE -> ACCEPTING state = ACCEPTING; } else if (input ...) { something_else() // transition routine for IDLE -> REJECTING state = REJECTING; } else { complain(); // blocks as complain is a lengthy operation } I.e., how does "A" return to "resume" on the next invocation (do you have to split it out as an "intermediate sub-state?) or to the block *inside* complain()?