An alternative to threads is using an event (interrupt) mechanism coupled with a a "main loop" that runs the button and power down code, and a timer interval as the "scheduler" to figure out which piece of code to run next. In this case there are three types of events that you need to deal with:
- button1 or button2 pressed
- power down signal
- timer signal, in an interval of say every 500ms
The idea is as follows:
- each time a button gets pressed, remember which button this was
- each time the timer fires, check which piece of the (button) event code is supposed to run next
- run the event code as part of the main loop
- split the event code in multiple pieces, after each piece check if the power down signal has occurred. If so, exit.
In the timer handler, check which part of the event code is supposed to run next, according to whatever button was figured in step 1. This is the "scheduler". In case of the power down signal, remember not to run any further button code, and in the main loop, run the power down code instead.
The main loop does exactly as it's name suggests:
interrupted = false; // assigned true on alternative button pressed
stopped = false; // assigned true at the end of power down
while(!stopped) {
while(!interrupted) {
run the code (piece of event code) determined by the scheduler
}
}
EDIT: explaining the example in more detail:
Wait, that's just the same as the OP example, but more complicated!?
No. Here the event handling, scheduling and execution are factored out and do not pollute the "buttons' code". Rather, the button code is kept simple and does not "know" of any partitions, nor does it need to provide for "cancellation" logic. Note that splitting the event code means that each piece is essentially a simple, seperate method whose execution is triggered from the main loop. There are no "if-ladders" as by OP's example. This keeps the actual logic readable and maintainable.
What if the event code is supposed to run only once?
The scheduler can also be extended to allow the event code, or some parts of it, to run only once. For this introduce a data structure that keeps track of which piece has run. Every time the scheduler runs, it updates the data structure and depending on the conditions you set for each piece of code, decides whether it should be scheduled or execution.
Why not run the button code directly in each event handler?
You could also run the button code directly in step 1, but this would make the UI sluggish, as it wouldn't respond until the code has finished to run. This is why the the timer handler needs to implement a scheduler. It determines which code to run. The actual code only gets to run on the main loop.
Why not run button code within the timer handler?
You could also run the buttons' code directly within the timer handler. The downside is that you'd have to ensure the code does not overrun the length of the timer interval to avoid interrupt overflows, or worse.
Isn't this too complex?
This design may seem overly complicated at first, but it makes sure the system continues to run smoothly by separating UI, scheduling and actual code running. The alternative, of course, is to use threads, but then the whole point of this answer is to show a solution withouth threads.
Are there improvements, e.g. for real time constraints?
Essentially, this all boils down to a scheduling problem. See Scheduling Algorithms (Wikipedia) for more sophisticated approaches, e.g. to deal with real time requirements.