You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs/device/reactive.md
+36-27Lines changed: 36 additions & 27 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -4,25 +4,27 @@
4
4
5
5
What sort of a *computing system* is the micro:bit?
6
6
7
-
## ~hint
7
+
### ~hint
8
+
9
+
#### Types of computing systems
8
10
9
11
There are different types of computing systems, to address different kinds of problems that arise in practice: *transaction processing systems* are used by banks to handle huge numbers of financial transactions by their customers; *distributed systems* make a set of networked computers appear as one big computer (like Google’s search engine); there are also *parallel systems*, such as graphic cards, which perform a huge number of primitive operations simultaneously, using a great number of small processing cores.
10
12
11
-
## ~
13
+
###~
12
14
13
-
The micro:bit is a *reactive system* – it reacts continuously to external events, such as a person pressing the **A** button of the micro:bit or shaking the device. The reaction to an event may be to perform a computation, update variables, and change the display. After the device reacts to an event, it is ready to react to the next one. If this sounds like a computer game, that’s because most computer games are reactive systems too!
15
+
The micro:bit is a *reactive system* – it reacts continuously to external events, such as a person pressing the **A** button of the micro:bit or shaking the device. The reaction to an event may be to perform a computation, update variables, and change the display. After the device reacts to an event, it is ready to react to the next one. If this sounds like a computer game, that’s because most computer games are reactive systems too!
14
16
15
17
## Responsiveness
16
18
17
-
We want reactive systems to be responsive, which means to react in a timely manner to events. For example, when you play a computer game, it’s frustrating if you press a button to make a character jump, but it doesn’t immediately jump. A delay in reacting, or lack of responsiveness, can be the difference between life and death, both in the real and virtual worlds.
19
+
We want reactive systems to be responsive, which means to react in a timely manner to events. For example, when you play a computer game, it’s frustrating if you press a button to make a character jump, but it doesn’t immediately jump. A delay in reacting, or lack of responsiveness, can be the difference between life and death, both in the real and virtual worlds.
18
20
19
-
Let’s consider a simple example: you want to program your micro:bit to accurately count the number of times the **A** button has been pressed and continuously display the current count on the 5x5 [LED screen](/device/screen). Because the LED screen is small, we can only display one digit of a number at a time on it. The [show number](/reference/basic/show-number) function will scroll the digits of a number across the screen so you can read it.
21
+
Let’s consider a simple example: you want to program your micro:bit to accurately count the number of times the **A** button has been pressed and continuously display the current count on the 5x5 [LED screen](/device/screen). Because the LED screen is small, we can only display one digit of a number at a time on it. The [show number](/reference/basic/show-number) function will scroll the digits of a number across the screen so you can read it.
20
22
21
-
Let’s say that the current count is 42 and the number 42 is scrolling across the LED screen. This means there is some code executing to perform the scroll. So, what should happen if you press the **A** button during the scroll? It would be a bad idea to ignore the button press, so some code should record the occurrence of the button press. But we just said there already is code running in order to scroll the number 42! If we wait until the code scrolling the 42 has finished to look for a button press, we will miss the button press. We want to avoid this sort of unresponsiveness.
23
+
Let’s say that the current count is 42 and the number 42 is scrolling across the LED screen. This means there is some code executing to perform the scroll. So, what should happen if you press the **A** button during the scroll? It would be a bad idea to ignore the button press, so some code should record the occurrence of the button press. But we just said there already is code running in order to scroll the number 42! If we wait until the code scrolling the 42 has finished to look for a button press, we will miss the button press. We want to avoid this sort of unresponsiveness.
22
24
23
25
## Concurrency
24
26
25
-
To be responsive, a reactive system needs to be able to do several things at the same time (concurrently), just like you can. But the micro:bit only has one CPU for executing your program, which means it can only execute one program instruction at a time. It can, however, execute millions of instructions in a single second. This points the way to a solution.
27
+
To be responsive, a reactive system needs to be able to do several things at the same time (concurrently), just like you can. But the micro:bit only has one CPU for executing your program, which means it can only execute one program instruction at a time. It can, however, execute millions of instructions in a single second. This points the way to a solution.
26
28
27
29
Think about how a motion picture projector works - it projects only 24 frames per second, yet this is good enough to provide the illusion of fluid motion on the screen. The micro:bit can execute millions of instructions per second, so it seems quite possible for the device to both to smoothly scroll the number 42 across the LED screen while looking for button presses and counting them.
28
30
@@ -36,19 +38,19 @@ In order to be responsive, we would like to *interrupt* the execution of sequenc
36
38
37
39

38
40
39
-
The result is that it takes sequence **S1** a little longer to complete, due to the interruptions to execute sequence **S2**, but we are checking often enough to detect a press of button **A** . When **S2** detects a press of button **A**, then the sequence **S3** can be executed before **S1** resumes:
41
+
The result is that it takes sequence **S1** a little longer to complete, due to the interruptions to execute sequence **S2**, but we are checking often enough to detect a press of button **A** . When **S2** detects a press of button **A**, then the sequence **S3** can be executed before **S1** resumes:
40
42
41
43

42
44
43
45
As we’ll soon see, there are other choices for how the sequences can be ordered to achieve the desired result.
44
46
45
47
## The micro:bit scheduler and queuing up subprograms
46
48
47
-
The micro:bit’s *scheduler* provides the capability to concurrently execute different code sequences, relieving us of a lot of low-level programming. In fact, scheduling is so useful that it is a part of every *operating system*!
49
+
The micro:bit’s *scheduler* provides the capability to concurrently execute different code sequences, relieving us of a lot of low-level programming. In fact, scheduling is so useful that it is a part of every *operating system*!
48
50
49
51
The first job of the scheduler is to allow multiple *subprograms* to be queued up for later execution. For our purposes, a subprogram is just a statement or sequence of statements in the context of a larger program. Consider the program below for counting button presses.
50
52
51
-
```typescript
53
+
```typescript-ignore
52
54
let count = 0
53
55
54
56
input.onButtonPressed(Button.A, () => {
@@ -63,14 +65,14 @@ basic.forever(() => {
63
65
The program above contains three statements that execute in order from top to bottom.
64
66
The first statement initializes the global variable `count` to zero.
65
67
66
-
```typescript
68
+
```typescript-ignore
67
69
// statement 1
68
70
let count = 0
69
71
```
70
72
71
-
The second statement informs the scheduler that on each and every event of the **A** button being pressed, a subprogram (called the event handler) should be queued for execution. The event handler code is contained within the braces `{...}`; it increments the global variable `count` by one.
73
+
The second statement informs the scheduler that on each and every event of the **A** button being pressed, a subprogram (called the event handler) should be queued for execution. The event handler code is contained within the braces `{...}`; it increments the global variable `count` by one.
The third statement queues a `forever` loop for later execution by the scheduler; the body of this loop (also inside the braces `{...}`) displays the current value of global variable `count` on the LED screen.
83
85
84
-
```typescript
86
+
```typescript-ignore
85
87
// statement 1
86
88
let count = 0
87
89
// statement 2
@@ -94,23 +96,23 @@ basic.forever(() => {
94
96
})
95
97
```
96
98
97
-
There are no more statements after the execution of these three statements, but this is not the end of program execution! That’s because the program queued the `forever` loop for execution by the scheduler (and registered an event handler for presses of button A).
99
+
There are no more statements after the execution of these three statements, but this is not the end of program execution! That’s because the program queued the `forever` loop for execution by the scheduler (and registered an event handler for presses of button A).
98
100
99
-
The second job of the scheduler is to periodically interrupt execution to read (poll) the various inputs to the micro:bit (the buttons, pins, etc.) and fire off events (such as “button A pressed”). Recall that the firing of an event causes the event handler subprogram associated with that event to be queued for later execution. The scheduler uses a timer built into the micro:bit hardware to interrupt execution every 6 milliseconds and poll the inputs, which is more than fast enough to catch the quickest press of a button.
101
+
The second job of the scheduler is to periodically interrupt execution to read (poll) the various inputs to the micro:bit (the buttons, pins, etc.) and fire off events (such as "button A pressed"). Recall that the firing of an event causes the event handler subprogram associated with that event to be queued for later execution. The scheduler uses a timer built into the micro:bit hardware to interrupt execution every 6 milliseconds and poll the inputs, which is more than fast enough to catch the quickest press of a button.
100
102
101
103
## Cooperative passing of control
102
104
103
105
How does the `forever` loop get to start execution? Furthermore, once the `forever` loop is running, how does any other subprogram (like the event handler that increments the count) ever get a chance to execute?
104
106
105
-
The answer is “cooperation” and “passing”. Think of a football team doing a drill – there is one ball and each footballer gets to dribble the ball for a certain number of touches, after which they pass to another footballer. A footballer who never passes prevents all other footballers from dribbling. A cooperative footballer always passes to some other footballer after taking a few touches.
107
+
The answer is "cooperation" and "passing". Think of a football team doing a drill – there is one ball and each footballer gets to dribble the ball for a certain number of touches, after which they pass to another footballer. A footballer who never passes prevents all other footballers from dribbling. A cooperative footballer always passes to some other footballer after taking a few touches.
106
108
107
109
If you hadn’t guessed already, a footballer represents subprogram and dribbling the ball corresponds to that subprogram executing. Only one subprogram gets to execute at a time, as there is only one ball (processor). Footballer Alice passing the ball to footballer Bob corresponds to stopping execution of Alice’s subprogram (and remembering where it stopped) and starting/resuming execution of Bob’s subprogram.
108
110
109
-
We will call this “passing control of execution” rather than “passing the ball”. However, in the world of the micro:bit, the concurrently executing subprograms are not aware of each other, so they don’t actually pass control directly to one another. Rather they pass control of execution back to the scheduler and the scheduler determines the subprogram to pass control to next. The programmer inserts a call to the `pause` function to indicate a point in the subprogram where control of execution passes to the scheduler. Also, when a subprogram ends execution, control passes to the scheduler.
111
+
We will call this "passing control of execution" rather than "passing the ball". However, in the world of the micro:bit, the concurrently executing subprograms are not aware of each other, so they don’t actually pass control directly to one another. Rather they pass control of execution back to the scheduler and the scheduler determines the subprogram to pass control to next. The programmer inserts a call to the `pause` function to indicate a point in the subprogram where control of execution passes to the scheduler. Also, when a subprogram ends execution, control passes to the scheduler.
110
112
111
113
Let’s take a look at the implementation of the `basic.forever` function to see an example of cooperative scheduling:
112
114
113
-
```typescript
115
+
```typescript-ignore
114
116
function forever_(body: () => void) {
115
117
control.inBackground(() => {
116
118
while(true) {
@@ -121,9 +123,17 @@ function forever_(body: () => void) {
121
123
}
122
124
```
123
125
124
-
The `forever` loop actually is a function that takes a subprogram (another function) as a parameter. The function uses the `control.inBackground` function of the micro:bit runtime to queue a `while true` loop for execution by the scheduler. The while loop has two statements. The first statement runs the subprogram represented by the `body` parameter. The second statement passes control to the scheduler (requesting to “sleep” for 20 milliseconds).
126
+
The `forever` loop actually is a function that takes a subprogram (another function) as a parameter. The function uses the `control.inBackground` function of the micro:bit runtime to queue a `while true` loop for execution by the scheduler. The while loop has two statements. The first statement runs the subprogram represented by the `body` parameter. The second statement passes control to the scheduler (requesting to "sleep" for 20 milliseconds).
127
+
128
+
Though the `while true` loop will repeatedly execute the body subprogram, between each execution of the body it will permit the scheduler to execute other subprograms. If the while loop did not contain the call to `pause`, then once control passed into the while loop, it would never pass back to the scheduler and no other subprogram would be able to execute (unless the body subprogram contained a call to `pause` itself).
129
+
130
+
### ~hint
125
131
126
-
Though the `while true` loop will repeatedly execute the body subprogram, between each execution of the body it will permit the scheduler to execute other subprograms. If the while loop did not contain the call to `pause`, then once control passed into the while loop, it would never pass back to the scheduler and no other subprogram would be able to execute (unless the body subprogram contained a call to `pause` itself).
132
+
#### Pauses within blocks
133
+
134
+
Certain blocks may contain a `pause` within their code to allow execution control to return to the scheduler. As an example, when a device is interacting with the code in a block, control can return to the scheduler to allow other subprograms run while that device is taking time to respond.
135
+
136
+
### ~
127
137
128
138
## Round-robin scheduling
129
139
@@ -141,20 +151,20 @@ Let’s go back to the `count button presses` program and revisit its execution
141
151
2. Set up the event handler for each press of button **A**
142
152
3. Queue the forever loop to the run queue
143
153
144
-
The program then ends execution and control passes back to the scheduler. Let’s assume the user has not pressed any buttons . The scheduler finds the `forever` loop in the run queue and passes control to it. The loop first calls `basic.showNumber(0)`. In the diagram below, we use “Show 0” to refer to the execution of this function:
154
+
The program then ends execution and control passes back to the scheduler. Let’s assume the user has not pressed any buttons . The scheduler finds the `forever` loop in the run queue and passes control to it. The loop first calls `basic.showNumber(0)`. In the diagram below, we use "Show 0" to refer to the execution of this function:
145
155
146
156

147
157
148
158
149
-
While "Show 0" (the blue sequence) is running, periodic interrupts by the scheduler (every 6 milliseconds) poll for button presses and queue an event handler for each press of button **A**. Let’s say that one button press takes place during this time, as shown above. This will cause an event handler (labelled “inc”) to be queued for later execution by the scheduler. Once the "Show 0" has completed, the loop then calls `basic.pause(20)` to put the forever loop to sleep for 20 milliseconds and give the scheduler an opportunity to run any newly queued event handler. Control passes to the “inc” event handler which will increment the global variable `count` from 0 to 1 and then complete, returning control to the scheduler. At some point, the `forever` loop moves from the sleep queue to the run queue; the `forever` loop then will resume and call `basic.showNumber(1)`.
159
+
While "Show 0" (the blue sequence) is running, periodic interrupts by the scheduler (every 6 milliseconds) poll for button presses and queue an event handler for each press of button **A**. Let’s say that one button press takes place during this time, as shown above. This will cause an event handler (labelled "inc") to be queued for later execution by the scheduler. Once the "Show 0" has completed, the loop then calls `basic.pause(20)` to put the forever loop to sleep for 20 milliseconds and give the scheduler an opportunity to run any newly queued event handler. Control passes to the "inc" event handler which will increment the global variable `count` from 0 to 1 and then complete, returning control to the scheduler. At some point, the `forever` loop moves from the sleep queue to the run queue; the `forever` loop then will resume and call `basic.showNumber(1)`.
150
160
151
-
## Final thoughts
161
+
## Final comments
152
162
153
-
Through this example, we have seen that the micro:bit scheduler enables you to create a program that is composed of concurrent subprograms. In essence, the programmer needs to only think about the concurrent subprograms cooperatively passing control back to the scheduler, making sure no subprogram hogs control (or “dribbles the ball without passing”) for too long. While a subprogram runs, the scheduler polls the buttons and other IO peripherals at a high frequency in order to fire off events and queue event handlers for later execution, but this is invisible to the programmer.
163
+
Through this example, we have seen that the micro:bit scheduler enables you to create a program that is composed of concurrent subprograms. In essence, the programmer needs to only think about the concurrent subprograms cooperatively passing control back to the scheduler, making sure no subprogram hogs control (or "dribbles the ball without passing") for too long. While a subprogram runs, the scheduler polls the buttons and other IO peripherals at a high frequency in order to fire off events and queue event handlers for later execution, but this is invisible to the programmer.
154
164
155
165
As a result, you can easily add a new capability to the micro:bit by just adding a new subprogram. For example, if you want to add a reset feature to the counter program, all you need to do is add a new event handler for a press of button **B** that sets the global variable "count" to zero, as shown below:
0 commit comments