Concurrent Execution

Thread Starter

Embededd

Joined Jun 4, 2025
157
I'm trying to understand the exact meaning of concurrent execution in the context of a microcontroller. An MCU can execute only the main code or an ISR at any given time. When an interrupt occurs, the MCU pauses the main code, executes the ISR, and then resumes the main code. Since the MCU switches between these two, is this considered concurrent execution, or does concurrency require something different?
 

WBahn

Joined Mar 31, 2012
32,862
I'm trying to understand the exact meaning of concurrent execution in the context of a microcontroller. An MCU can execute only the main code or an ISR at any given time. When an interrupt occurs, the MCU pauses the main code, executes the ISR, and then resumes the main code. Since the MCU switches between these two, is this considered concurrent execution, or does concurrency require something different?
This question is gray because the answer depends on what is meant by concurrent and what the ISR is doing.

For instance, consider an old PC running DOS. It could run one program at a time. But yet that PC had lots of interrupts happing constantly do things like respond to a keyboard press or release, or update the clock. So are these concurrent operations? Technically you could call them that, but they almost never are described that way.

Concurrency is generally applied at a particular level of abstraction to describe the situation in which more than one task is able to advance seemingly at the same time, whether it be truly simultaneously via multiple cores or processors, or synthetically by quickly rotating control of the processor amongst the tasks. If you are writing an operating system, you are operating at a level in which things are happening concurrently but are things that people running programs don't see and aren't aware of. To them, concurrency means multiple applications running at the same time.
 

Thread Starter

Embededd

Joined Jun 4, 2025
157
This question is gray because the answer depends on what is meant by concurrent and what the ISR is doing.
I came across the statement, " Use an RTOS when you have multiple independent tasks, concurrent operation, and strict timing requirements." Instead of starting with the RTOS context, I first tried to understand concurrency in a simpler way. For example, in bare-metal programming on a single-core MCU, there may be a main task and one or more interrupt-driven tasks (UART receive, timer interrupt, external interrupt, etc.). When an interrupt occurs, the MCU switches from the main code to the ISR and then returns to the main code. Although only one task is executing at any given time, the MCU switches between them as required. Because of that, I initially thought this might be what is meant by concurrent execution.

Is this a reasonable way to think about concurrency before moving on to RTOS concepts?
 

WBahn

Joined Mar 31, 2012
32,862
I came across the statement, " Use an RTOS when you have multiple independent tasks, concurrent operation, and strict timing requirements." Instead of starting with the RTOS context, I first tried to understand concurrency in a simpler way. For example, in bare-metal programming on a single-core MCU, there may be a main task and one or more interrupt-driven tasks (UART receive, timer interrupt, external interrupt, etc.). When an interrupt occurs, the MCU switches from the main code to the ISR and then returns to the main code. Although only one task is executing at any given time, the MCU switches between them as required. Because of that, I initially thought this might be what is meant by concurrent execution.

Is this a reasonable way to think about concurrency before moving on to RTOS concepts?
It really comes down to context and what is considered a "task".

When you are sitting at your computer and you have a Word document open and are playing some music in another app (and that's all you have open), you probably look at that as being two things running concurrently.

But if you look in your Task Manager, you will likely see hundreds of processes that are all running concurrently in exactly the same way. They are constantly updating timers, checking the network connections, talking to the hard disk, getting input from the keyboard, interacting with the mouse, sending data to the screen(s). But you don't think of them because they are at a completely different layer of abstraction, and so they get lumped into a single black box that is completely ignored. Even the fact that the operating system itself is running concurrently with just a single open application is seldom thought of at this level.

But if you are programming on bare metal, you often need to look at these low-level tasks as separate tasks that have to be managed and resources, including CPU time, shared between.

But these are low-level housekeeping tasks that any system beyond the most simple ones have to deal with, so referring to them as "concurrent", even though technically defensible, makes little sense because it becomes effectively meaningless since 99.999+% of systems are then "concurrent" systems.

Think of it this way. I don't have a PC because I want to talk to a keyboard or update a timer. I don't even have a PC because I want to run an operating system. I have a PC because I want to edit a Word document and listen to some music. THOSE are the tasks that I interested in running concurrently. The old DOS machines had to do all of the low-level housekeeping tasks "concurrently", but you couldn't have two user programs running at the same time. So it was considered to not support concurrent execution.

Similarly, if I program an MCU it isn't because I want to receive something from a UART or update a timer, its because I want to control the temperature of boiler and the speed of a blower. If those are separate tasks and I write my program so that they can both progress at the same time, then they are running concurrently.
 

panic mode

Joined Oct 10, 2011
4,994
I'm trying to understand the exact meaning of concurrent execution in the context of a microcontroller. An MCU can execute only the main code or an ISR at any given time. When an interrupt occurs, the MCU pauses the main code, executes the ISR, and then resumes the main code. Since the MCU switches between these two, is this considered concurrent execution, or does concurrency require something different?
that only holds for a single core MCU. but if you need muscle, why limit yourself to a single core? or even a single MCU....

to me concurrent means "at the same time". but MCUs operate on different time scale - they run much faster than our senses perceive things. that means MCU could as well do many things in succession. for a human observer it would look as they are all progressing "at the same time". this can employ different techniques (interrupts, scheduling, ...).

using FPGA one can do awesome parallel computation and often have one or more CPU cores as bonus - all in same IC. so what exactly is your real objective?
 
Last edited:

Futurist

Joined Apr 8, 2025
761
I'm trying to understand the exact meaning of concurrent execution in the context of a microcontroller. An MCU can execute only the main code or an ISR at any given time. When an interrupt occurs, the MCU pauses the main code, executes the ISR, and then resumes the main code. Since the MCU switches between these two, is this considered concurrent execution, or does concurrency require something different?
Forget about CPUs, indulge me here, I've designed and written software schedulers and the best analogies are always people.

Imagine you - a human - has to paint a room and cook dinner for your kids and read them a bedtime story.

Not concurrent means you do one of these tasks to completion and then and only then, start the other and do that to completion.

Concurrent means starting an activity irrespective of whether you already started some other activity.

You can easily envisage painting the room, stopping, preparing the raw food, doing some more painting, putting the pots on the stove, going back to the painting, stirring the pots, going back to the painting, dishing out the food, going back to the painting, etc etc.

That's ultimately what it means, that's the essence of it, two unrelated activities, that are interleaved, each progressing, not forced to do one complete activity before starting the next activity.

There's just one person but two distinct, unrelated activities simultaneously underway.
 

WBahn

Joined Mar 31, 2012
32,862
Forget about CPUs, indulge me here, I've designed and written software schedulers and the best analogies are always people.

Imagine you - a human - has to paint a room and cook dinner for your kids and read them a bedtime story.

Not concurrent means you do one of these tasks to completion and then and only then, start the other and do that to completion.

Concurrent means starting an activity irrespective of whether you already started some other activity.

You can easily envisage painting the room, stopping, preparing the raw food, doing some more painting, putting the pots on the stove, going back to the painting, stirring the pots, going back to the painting, dishing out the food, going back to the painting, etc etc.

That's ultimately what it means, that's the essence of it, two unrelated activities, that are interleaved, each progressing, not forced to do one complete activity before starting the next activity.

There's just one person but two distinct, unrelated activities simultaneously underway.
Nice analogy -- for thinking of it at the application level, which is the context we usually think of it. But the TS is asking something more akin to does interrupting work to get a drink of water, or go to the bathroom, or blow your nose, constitute concurrent processing? My position is that, while you can make an argument that they are, doing so for such low-level housekeeping tasks renders the whole point of even using the term "concurrent" meaningless. It only has value if it distinguishes between a system that is concurrent from one that is not, which argues that the term is best employed at the application level and not much below that.
 
Nice analogy -- for thinking of it at the application level, which is the context we usually think of it. But the TS is asking something more akin to does interrupting work to get a drink of water, or go to the bathroom, or blow your nose, constitute concurrent processing? My position is that, while you can make an argument that they are, doing so for such low-level housekeeping tasks renders the whole point of even using the term "concurrent" meaningless. It only has value if it distinguishes between a system that is concurrent from one that is not, which argues that the term is best employed at the application level and not much below that.
Well I wouldn't want to imply that concurrency is only possible with interrupts, that's something important to understand for someone unfamiliar with the ideas. Also my analogy paid no attention to the decision making process with respect to when to stop/start either of the two activities.

Essentially we have a single general purpose worker and multiple activities that do not run serially, nothing special, no conceptual challenges, if the student is confused then that's because of something else, bad assumptions, misconceptions and so on, the analogy (like all analogies) is intended to isolate the abstract from the concrete.

Concurrency is not confined to digital computers.

Consider recursion. Often students are confused by people saying "the function calls itself", this is because in their mind is an implicit context associated with the function and "calls itself" makes no sense, so I used to describe recursion as a function calling an identical copy of itself, and they'd quickly grasp the idea, even though there are no copies, perceiving it as copies makes it much easier for some people to grasp the distinct contexts of each invocation.

Once they grasp this, its easier to go from that to "calls itself".

Using a simple recursive factorial function, writing out the function four times (exact copies) from left to right with a simple argument like 4, they quickly begin to grasp what's going on. Then we can point out how we really don't need to write it four times, have four copies, but that's often not obvious at the beginning of the class.
 
Last edited:

MrChips

Joined Oct 2, 2009
34,818
You would expect that "concurrency" would mean the same thing to everyone, i.e. occurring at the same time. Not so.

The same goes for "real time process".
Where computers are involved, there is no such thing as a "real time processor". The computer has to collect data, process the data, and produce a result. Each step takes time and hence the result comes with a time delay, from the point of the initial input to final result.

In reality, we come to accept a process as being accomplished in "real time" when the delay is not significant when compared to other process or reaction times.

For example, a foreign language speech translator, from audio capture of foreign language speech to audio output in the listener's language can be considered to be occurring in "real time" if the processing delay is within acceptable limits.

Similarly, "concurrent processes" does not mean "occurring at the same time". Instead, we would accept it to mean that multiple processes "appear" to occur at the same time. It does not matter whether the process uses blocking or non-blocking polling, or interrupts. So long as all processes are completed within an acceptable timeline.

Having said that, a truly "concurrent processor" would have to use a multi-core or multi-processor system.
Failing that, a single core system can use interrupts and direct memory access (DMA) to its advantage in order to process time-critical events.

The bottom line is: one has to establish what time-delay from input to response is acceptable and not acceptable.
 

Thread Starter

Embededd

Joined Jun 4, 2025
157
The bottom line is: one has to establish what time-delay from input to response is acceptable and not acceptable.
I usually follow sequential style one loop. I haven't yet encountered a situation where the MCU was too slow to complete operation. As far as I understand, the MCU is typically much faster than the external devices it interfaces with, so it can react to inputs very quickly.

So when you talk about acceptable and unacceptable response times, do you mean that the program's structure can cause delays in reacting to an input, or do you mean that the MCU itself may be too slow to react to an input?
 
I usually follow sequential style one loop. I haven't yet encountered a situation where the MCU was too slow to complete operation. As far as I understand, the MCU is typically much faster than the external devices it interfaces with, so it can react to inputs very quickly.

So when you talk about acceptable and unacceptable response times, do you mean that the program's structure can cause delays in reacting to an input, or do you mean that the MCU itself may be too slow to react to an input?
When an interrupt does arise, it usually masks lower priority interrupts and they stay masked until the interrupt handler exits. So if an interrupt handler takes a "long" time to execute, some other interrupts might be blocked and the handling of them is delayed.

That's on kind of delay, another is when the arrival rate of work is so high, that the work begins to queue up and so items of work are delayed while they are in the "queue" as the queue grows the delays become greater too (known as the producer/consumer problem).

One can easily make up an analogy with a person, say a cook in a restaurant, if every order takes 15 minutes to complete then when we get orders at the rate of two/hour we're good, but if they arrive every 10 minutes or so, then a backlog begins to accumulate, someone placing an order when there are ten orders ahead not yet completed, might have to wait over two hours for their food!
 
Last edited:

MrChips

Joined Oct 2, 2009
34,818
I usually follow sequential style one loop. I haven't yet encountered a situation where the MCU was too slow to complete operation. As far as I understand, the MCU is typically much faster than the external devices it interfaces with, so it can react to inputs very quickly.

So when you talk about acceptable and unacceptable response times, do you mean that the program's structure can cause delays in reacting to an input, or do you mean that the MCU itself may be too slow to react to an input?
Program structure, MCU through-put, hardware delays, everything that takes time.

Use of interrupts is called preemptive processing. There are processes that take priority over processes that can be suspended and delayed. For example, if you have a fire alarm activated, it might take priority over other events.

If you are using a software or hardware mechanism for a timebase clock, why poll for a flag when the processor can attend to other tasks? Similarly, if you are sending or receiving UART data, you don't have to suspend other processes while waiting for the next data to be transmitted or received.

In many applications, interrupt mechanism is too slow. For example, you need to digitize a signal at a sampling rate of 50 Msps without any breaks. DMA can allow the ADC to sample and store data straight into memory while the processor is doing something else.
 

WBahn

Joined Mar 31, 2012
32,862
I usually follow sequential style one loop. I haven't yet encountered a situation where the MCU was too slow to complete operation. As far as I understand, the MCU is typically much faster than the external devices it interfaces with, so it can react to inputs very quickly.

So when you talk about acceptable and unacceptable response times, do you mean that the program's structure can cause delays in reacting to an input, or do you mean that the MCU itself may be too slow to react to an input?
You haven't encountered it because you haven't done anything that requires fast response. Maybe you never will and your approach will always work for you. But that doesn't mean that it is safe to assume that your MCU will always be able to outpace what it is being used for with so much margin that you can use that approach.

As to your last question, the answer is yes. It doesn't matter why an input is not responded to within the necessary time limit, in in order to respond within that limit, everything must be designed and implemented so that, together, they can satisfy that requirement. If it isn't meeting requirements, the solution might be as simple as using a faster MCU. Or it might be possible to rewrite the code to make the loop faster. Or it might be possible to use interrupts (or use them better). Or redesign the hardware. Or use multiple MCU to split the tasks. Or some combination of all of these things. Or even look at the requirement itself and determine if it can't be relaxed. Maybe it is too conservative to begin with. Or maybe something can be done in the external system to free up some margin.
 
Top