What is an operating system — theory with your laptop on a study afternoon, a write() call and a CPU that never rests (and the three programs that weren’t running at the same time)
First operating systems class in IC2. The lecturer puts up a photo of a laptop with Spotify playing, VS Code compiling the lab assignment and the browser downloading a PDF, and asks: “If this laptop has a CPU with a single core, how many programs are running at the same time?”. Me, very sure of myself: “Three, you can see them in the photo”. Answer: one. At any instant the CPU runs the instructions of a single program; the other two are waiting for the network, the disk or the sound card, or waiting for their turn. What looks like “at the same time” is a trick of the operating system, and it is so good we don’t even notice it.
Today we start the operating systems part of the IC2 theory. After three networking topics (the last one was IP addressing and subnets), it’s time to understand the software that sits underneath everything you use: what an operating system is, how it acts as an interface between your programs and the hardware, how it shares out resources, what its great inventions were and what kinds of systems exist. The guiding example is your laptop on a study afternoon, and at the end we’ll simulate it in Python to measure how hard the CPU works. When you finish, practise with the exam-style exercises for this topic.
Table of Contents
What an operating system is
Let’s start with the definition that comes up in the exam. An operating system (OS) is the software that manages a computer’s hardware and provides an execution environment for the users’ application programs.
Look at the two halves of the sentence: downwards, it manages the hardware; upwards, it gives the applications an environment. Trick questions usually turn it around (“the software that manages the applications and gives the hardware an environment”) or mix it up with something else (the hardware, a compiler, the applications that come pre-installed).
There is no definition that everyone accepts. The course notes collect several: software that acts as an intermediary between users and applications and the hardware; a set of programs that manage resources, optimise their use and resolve conflicts; and even, half-jokingly, “anything a vendor sells you as an operating system”. They all say the same thing from different angles.
Where it is: the layers of your laptop
Where exactly is that software? Look at the drawing below: a computer system can be seen as four layers. At the top are you (or any user: people, machines or other computers). Below, the applications: Spotify, VS Code, the browser, which use the resources to solve the user’s problems. Then the operating system, which controls and coordinates the use of the hardware among applications and users. And at the very bottom, the hardware: CPU, memory, disk, Wi-Fi, sound card.
Inside the OS itself there are two pieces worth telling apart:
- The kernel: the only program that runs at all times while the computer is on. It is the OS in the strict sense.
- System programs: they come with the operating system but are not part of the kernel, like the shell or the file explorer. They open and close like any other program.
Everything else (whatever is not associated with the system) is an application. So no: the browser is not part of the OS, even if it comes installed from the factory.
What it is for: goals and roles
The notes give the OS four goals:
- Manage resources efficiently.
- Make interacting with the computer easier.
- Provide an environment to run applications.
- Make it easier for software and hardware to evolve: if you swap your disk for a faster one, your programs keep working without touching a single line.
And they describe it with three roles, three metaphors that appear in the exam as matching questions:
| Role | What it does | On your laptop |
|---|---|---|
| Traffic police | Organises resources, handles conflicts when several ask for the same thing and protects against errors and unwanted use | If a browser tab hangs, it doesn’t take VS Code down with it |
| Facilitator | Shares out what everybody needs and offers an “extended machine” that hides the hardware so programming is simpler, faster and less error-prone | VS Code saves a file without knowing which disk you have |
| Government | Provides a share of the resources when needed and offers standard interfaces to share them | Spotify and the browser share the Wi-Fi without fighting |
Thinking that the OS does the user’s useful work. The OS does no productive work for you: it doesn’t write your document or compile your assignment. Applications do that; the OS shares out the hardware so they can.
Where can you find an OS? Practically everywhere: in your PC, in a phone, in a TV, in a smartwatch, in a connected fridge and in the computers of a plane. A simple Arduino, on the other hand, usually runs a single program directly on the hardware, with no OS.
The operating system as an interface
First way of looking at the OS: as a layer that wraps the hardware and offers on top an abstract machine (or “extended machine”) that is more convenient than the real one. That layer does two things at once:
- It hides awkward hardware details: your program doesn’t know which disk sector each byte lands in or how to talk to the Wi-Fi card.
- It adds features the hardware doesn’t have: the disk only knows about blocks; the OS offers you files and folders. The CPU only runs instructions; the OS offers you processes that seem to have the machine all to themselves.
Saying the layer wraps the software or the applications. The layer wraps the hardware; applications sit on top and use it.
One interface for each kind of user
Who is that interface for? It depends on who sits in front of it. The drawing sums it up: the user and the look change, but every interface ends up in the kernel.
| Who | What environment the OS gives them | What it looks like |
|---|---|---|
| General users | Execution environment | GUI (graphical interface: windows, icons) or NUI (natural interface: voice, touch, gestures) |
| Administrators | Administration environment | CLI or command interpreter, the shell (bash, PowerShell) |
| Developers | Programming interface | The OS API: the system calls |
About the command interpreter (CLI): in some systems it is implemented inside the kernel and in others as a system program. It can take different forms (the different shells), it includes a simple language to give orders to the OS (load programs, work with files…) and some orders are built in while for others it calls other programs. If you followed the Linux topics, you already know it: it’s what’s behind the $ in your terminal.
System calls: how a program asks the OS for something
The developers’ interface is the most important one to understand how everything works inside. The OS offers developers and processes a set of public services reachable through an API: the system calls. They are usually not used directly but through the system libraries (in C, libc).
The example in the notes is UNIX write(), which writes a block of data to a file or to an I/O device. This is its prototype in C:
int write(int fd, void *buffer, size_t size);
Three arguments and a result. The drawing labels each part and, below, the path the request follows:
fdis the file descriptor: a number that identifies where we are going to write (an open file, the screen, a network socket).bufferis a pointer to the memory area where the data is.sizeis the length of the data in bytes.- The result is the number of bytes written. It may be less than
size, and a serious program checks it.
What matters is the path at the bottom: your process never touches the disk. It calls the library, the library makes the system call, the kernel checks that the descriptor is valid and that you have permission, and the device driver actually writes. If you want to see it with real code that runs, we did it in System calls in C.
If a question mentions “public OS services offered to developers through the system libraries”, it’s talking about system calls.
What do we gain by putting an interface in the middle?
Putting a layer between programs and hardware has a cost (one more indirection), so it has to pay off. It does, for six reasons the exam asks you to match:
| Benefit | What it means | Example on your laptop |
|---|---|---|
| Usability | The interface is more convenient than the hardware | You save with Ctrl+S, not by moving the disk head |
| Security | The vulnerabilities inside the hardware are hidden | A program can’t write wherever it likes on the disk |
| Portability | Software doesn’t depend on the specific hardware | VS Code works the same with an SSD or a spinning disk |
| Interoperability | Information is shared with other systems that use the same interface | A USB stick formatted on your laptop can be read on your classmate’s |
| Maintainability | The OS can be improved without forcing changes to user programs | An OS update doesn’t make you reinstall Spotify |
| Productivity | The sum of all the above | You program faster and with fewer errors |
The operating system as a resource manager
Second way of looking at the OS: as a resource manager. To understand it you need two words with an exam definition:
- Process: a program in execution. It is an active entity: it moves forward, instruction by instruction, and has a state at every moment.
- Resource: something physical or virtual that a process needs in order to run (CPU, memory, disk, network, a file). It is a passive entity.
And what is the difference between a program and a process? The program is a collection of instructions stored on disk (passive). The process is that program running. If you open VS Code twice, there is one program and two processes. Processes get a whole topic (number 6); here the idea is enough.
The OS as a referee
Now the problem: resources are scarce and processes compete for them. Your laptop has one CPU, a fixed amount of RAM and one disk, and on a study afternoon the compiler, the download and Spotify all want them at once. Someone has to decide, and that someone is the OS, acting as a referee or mediator that allocates resources fairly and efficiently.
Reading too fast and ticking “processes are scarce and resources compete for them”. It turns the sentence around. What is scarce is resources; what competes is processes.
The rules it decides with are the resource management policies, and they answer the four questions you see in the drawing: which process gets the resource, how much, when and for how long. Careful: which process, not which user.
These policies must meet three criteria:
- Optimise the performance of the system.
- Fairness in sharing: prevent a process from hogging resources and others from suffering starvation (waiting forever).
- Guarantee the security of the system, with its three elements, the CIA: confidentiality (intimacy, privacy), integrity (information doesn’t get corrupted) and availability (the system keeps providing service).
And here’s the interesting part: these criteria conflict. If you want maximum performance, give all the CPU to the compiler so it finishes as soon as possible; but then Spotify gets no turn and the music cuts out, and that isn’t fair. The OS always looks for a balance, never the maximum of everything.
What the OS manages
The list from the notes, which appears in the exam as a multiple-answer question:
- Processes: creating and deleting them, suspending and resuming them, and providing mechanisms for synchronisation, communication and deadlock handling.
- Memory: knowing which parts are in use and by whom, deciding which processes (or parts) move into and out of memory and allocating and freeing space.
- Files: creating and deleting files and directories, offering a logical, uniform view of storage and making backups.
- Mass storage devices, cache and input/output devices.
- Protection and security.
Topics 6 to 11 in this series are, one by one, these managers: processes, scheduling, concurrency, memory, virtual memory and files.
Multiprogramming: the trick of the CPU that never rests
Back to the opening question. A program doesn’t use the CPU all the time: it alternates CPU bursts (computing) with I/O waits (waiting for the network, the disk, the sound card). The PDF download, for example, computes for 10 ms and then waits 60 ms for data to arrive from the network.
Without multiprogramming, while a program waits for its I/O the CPU sits idle: nobody else can use it until that program has completely finished. With multiprogramming (also called multitasking) several processes are loaded in memory and, when one blocks waiting for its I/O, the CPU runs instructions from another one. The CPU and the devices work at the same time, and more jobs finish in less time.
The drawing shows your laptop’s afternoon with the exact data from the simulator at the end of the article: C is the compiler, D the download and M Spotify.
Both CPU rows do the same work: 140 ms of CPU in total. But one after another they take 360 ms and the CPU is busy only 39% of the time (140 / 360 = 0.39); multiprogrammed they take 190 ms and the CPU works 74% of the time (140 / 190 = 0.74). Multiprogramming doesn’t make the CPU faster: it fills the gaps left by the waits.
Saying that with multiprogramming, on a single CPU, processes run “in parallel”. At any instant there is only one on the CPU. Processes interleave their execution: it’s concurrency, not parallelism. Real parallelism only exists with several processors.
What changes in memory
To jump from one process to another, the processes have to be loaded in memory at the same time. That changes the picture, as the drawing shows: without multiprogramming there was the OS and one program; with multiprogramming there are several processes, each in its own area with free gaps in between.
The OS gives each process a private memory space: no process can access another one’s space (or the OS’s own). The crossed-out red arrow in the drawing is what would happen if VS Code tried to write into Spotify’s memory: the OS stops it.
New problems it brings
Having several processes at once is a huge step forward, but it opens questions that didn’t exist with a single program:
- When the CPU becomes free, which process do we give it to? That’s CPU scheduling (Topic 7).
- Competition for memory consumption: it has to be shared out (Topics 9 and 10).
- Protection of private memory areas.
- Conflicts when several access the same resource at once, and the risk of deadlock: two processes waiting for each other forever (Topic 8).
- And protection and security: how do we stop a process from damaging another one’s memory or the OS’s? How do we prevent it from accessing I/O directly, bypassing the policies? How do we guarantee that a user’s private data can’t be read by any process? How do we make sure only authorised people get into the system?
Operating system milestones
Some OS ideas changed computing forever. In the exam they’re asked as “historical achievements”, and the trick is to separate what the OS invented from what the hardware or programming languages invented:
| Milestone | What it solves | On your laptop |
|---|---|---|
| Multiprogramming | The CPU doesn’t sit idle while a process waits for its I/O | The compiler computes while the download waits for the network |
| Paging | Chop a program into pages and place them in different gaps of main memory | VS Code doesn’t need one huge contiguous free gap in RAM |
| Virtual memory | The program needn’t be entirely in main memory: the disk acts as an extension | You open more programs than fit in your RAM |
| File system | Store and find data and programs in secondary storage, organised into files and directories | Your IC2 notes folder |
| Uniform I/O interface | The same API for any device | write() works the same on a USB stick as on an SSD |
| Concurrent access control | Order access to a resource that several processes can’t use at once | Two programs want the printer: one waits |
| Protection and security | Nobody steps on or reads what isn’t theirs | Another user’s process can’t read your files |
Ticking multi-core processors, high-level languages or touch screens as OS milestones. They are advances in hardware or languages, not in the operating system.
Paging versus virtual memory
These two get mixed up all the time because virtual memory relies on paging. The drawing puts them side by side:
- Paging: the program is chopped into pages of the same size that are placed in different areas of main memory (which is also divided into pieces of that size). The whole program is in RAM, but spread out.
- Virtual memory: the program doesn’t need to be fully loaded in main memory; secondary storage is used as an extension of main memory. In the drawing, pages 2 and 3 stay on the disk until they’re needed.
Both are handled automatically, without the user or the programmer having to step in. You’ll see them in depth in Topics 9 and 10.
If an option mentions secondary memory or the cache when defining paging, it’s the trap. Paging only talks about main memory.
Uniform I/O interface and concurrent access control
The uniform I/O interface means offering developers a uniform API to access any device. Inside, each device has its driver, which is transparent to the end user. That achieves device independence: abstraction of the details of each class of peripheral, portability (the same code works with different devices), adaptation to future peripherals and more security, because direct access to devices can be forbidden.
Concurrent access control is the control of access to a resource that can’t be shared at the same time by several processes. Two processes can’t write to the same piece of a file at once, or print with their pages mixed up: the OS makes one wait. It’s the seed of Topic 8.
Types of systems
Computing isn’t just your laptop. The notes list many computing environments: personal computers, handheld devices (phones and tablets), embedded systems, servers and multiprocessors, server clusters, supercomputers, distributed systems, virtualised systems and the cloud. And, depending on how they are organised, these types of systems:
Batch, time sharing and real time
Three ways of sharing out CPU time, with very different goals. Compare them in the drawing:
- Batch processing: historically, the first OSs (early 1950s). The goal was to automate the running of jobs and increase processor use. Jobs were grouped into batches and run in sequence, without user control. The most primitive ones were sequential; multiprogramming was added at the end of the 1960s. The first control language was born to dictate tasks to the OS: JCL (Job Control Language).
- Time sharing: invented in the 1950s and commercialised in the 1960s, they aimed for interactivity. Each process gets a small periodic time slice and processes take turns on the CPU. If the slice is a few milliseconds, the user doesn’t notice the pauses. Besides, the same computer can be shared among many users.
- Real time: designed for tasks that must finish within a fixed deadline (industrial control, multimedia), with special scheduling algorithms. In hard real-time systems (industry, embedded systems such as a car’s brakes) missing a deadline is a failure, and they usually do without services that affect timing, such as virtual memory: fetching a page from disk takes a time that can’t be guaranteed.
Multi-user is not multitasking
A multi-user system recognises several access profiles with different privileges: permissions on files and applications, space or processor-time quotas, priority in accessing resources… It’s what you saw in Linux permissions.
Thinking multi-user and multitasking are the same. Your phone is multitasking (several apps at once) and one person uses it: there can be multitasking systems that aren’t multi-user.
Multiprocessors
Multiprocessors range from a few to thousands of processors. They’re classified in two ways, and the drawing puts the four acronyms together:
| Acronym | Question it answers | Meaning |
|---|---|---|
| SMP | Who runs what? | Symmetric multiprocessing: a task can run on any processor |
| AMP | Who runs what? | Asymmetric multiprocessing: there’s specialisation (for example, one processor runs the OS and others the user processes) |
| UMA | Where is memory? | Uniform Memory Access: shared memory, same access time for all |
| NUMA | Where is memory? | Non Uniform Memory Access: distributed memory, each processor has its own; another one’s is slower |
Distributed systems and virtual machines
A distributed system is a set of computers connected in a network and used as if it were a single system with many processors, a large shared memory and a large storage. There’s no “universal distributed system”, but there are services with distributed-system features: cloud services (Dropbox, Amazon) or the web itself.
A virtual machine is the software emulation of a physical machine: programs made for the emulated machine run on it. Advantage: you don’t need the original system. Drawback: emulation is slower. Historical examples: IBM VM (1960s), which gave each user their own virtual machine, and VMware, able to run Windows, Linux and macOS at the same time. Their uses:
- Creating protected environments: each virtual machine is isolated from the rest.
- Platform independence, like the Java virtual machine.
- Keeping old systems alive: MS-DOS or game console emulators.
- Development: writing and testing applications for hardware you don’t have.
If you followed the Fedora on VirtualBox guide, you’ve already used one.
Common mistakes in this topic
Confusing the operating system with applications or with system programs. The OS in the strict sense is the kernel; system programs come with it; applications aren’t part of the OS.
Confusing paging (chopping up in main memory) with virtual memory (not loading the whole program, using the disk as an extension).
Writing that the policy decides “which user” gets the resources. It decides which process, how much, when and for how long.
Ticking “the OS does productive work for the end user”. It doesn’t: it manages resources so applications can.
For questions about types of systems, link each one to its keyword: batch → sequential and unattended (JCL); time sharing → slices and interactivity; real time → deadlines; multi-user → profiles and privileges; distributed → many machines that look like one.
Check it with Python
Let’s measure multiprogramming instead of taking it on faith. This simulator reproduces your laptop’s afternoon: three programs alternating CPU and I/O bursts, first one after another and then multiprogrammed. Each letter of the CPU line is 10 ms; a dot means the CPU is idle.
# Multiprogramming simulator: how hard does your laptop CPU work?
# Each program alternates CPU and I/O bursts (in ms). Fixed data, no input().
PROGRAMS = { # name: [CPU, I/O, CPU, I/O, CPU]
'C': [40, 20, 40], # C = the VS Code compiler (almost all CPU)
'D': [10, 60, 10, 60, 10], # D = the PDF download (waits for the network)
'M': [10, 40, 10, 40, 10], # M = Spotify (waits for the disk and the sound card)
}
STEP = 10 # each letter of the CPU line is 10 ms
def simulate(multi):
left = {p: list(r) for p, r in PROGRAMS.items()} # bursts still to do
ready, in_io, cpu, line, end = list(PROGRAMS), [], None, '', {}
while any(left.values()):
# without multiprogramming nobody gets the CPU while another waits for its I/O
if cpu is None and ready and (multi or not in_io):
cpu = ready.pop(0)
line += cpu or '.' # '.' = CPU idle
for p in ([cpu] if cpu else []) + in_io:
left[p][0] -= STEP # the CPU and each I/O move on (each on its own device)
for p in [p for p in in_io if left[p][0] == 0]:
left[p].pop(0); in_io.remove(p) # its I/O is over: back to the ready queue
ready.insert(len(ready) if multi else 0, p)
if cpu and left[cpu][0] == 0:
left[cpu].pop(0)
if left[cpu]:
in_io.append(cpu) # it blocks waiting for I/O and releases the CPU
else:
end[cpu] = len(line) * STEP # it has completely finished
cpu = None
return line, end
for multi in (False, True):
line, end = simulate(multi)
busy, total = STEP * sum(c != '.' for c in line), STEP * len(line)
print('Multiprogrammed:' if multi else 'One after another:')
print(f' CPU |{line}|')
print(' finish: ' + ', '.join(f'{p} at {t} ms' for p, t in end.items()))
print(f' total {total} ms, CPU busy {busy} ms, usage {100 * busy / total:.0f} %')
Bursts always follow the pattern CPU, I/O, CPU…, and we assume each I/O goes to its own device (network, disk, sound card), so several waits can progress at once. The CPU, on the other hand, is a single one. This is the real output of the only run:
One after another: CPU |CCCC..CCCCD......D......DM....M....M| finish: C at 100 ms, D at 250 ms, M at 360 ms total 360 ms, CPU busy 140 ms, usage 39 % Multiprogrammed: CPU |CCCCDMCCCCMD...M..D| finish: C at 100 ms, M at 160 ms, D at 190 ms total 190 ms, CPU busy 140 ms, usage 74 %
Let’s check the numbers by hand. CPU busy time is the same in both modes: C uses 40 + 40 = 80 ms, D uses 10 + 10 + 10 = 30 ms and M another 30 ms, for a total of 80 + 30 + 30 = 140 ms. One after another, C takes 40 + 20 + 40 = 100 ms, D takes 10 + 60 + 10 + 60 + 10 = 150 ms and M 10 + 40 + 10 + 40 + 10 = 110 ms: 100 + 150 + 110 = 360 ms, and 140 / 360 = 0.39, that is 39%. Multiprogrammed, 140 / 190 = 0.74, that is 74%.
The line that decides whether there is multiprogramming
The whole difference between the two modes is in one condition:
# without multiprogramming nobody gets the CPU while another waits for its I/O
if cpu is None and ready and (multi or not in_io):
cpu = ready.pop(0)
The CPU is only given to someone if it’s free (cpu is None) and there’s someone in the ready queue. With multi set to True, that’s enough. Without multiprogramming it also requires not in_io: if any process is waiting for its I/O, nobody else can get in. That’s exactly what happened in the most primitive batch systems: the CPU waited along with the program.
What happens when an I/O finishes
The other piece is where the process goes back to when its wait is over:
for p in [p for p in in_io if left[p][0] == 0]:
left[p].pop(0); in_io.remove(p) # its I/O is over: back to the ready queue
ready.insert(len(ready) if multi else 0, p)
With multiprogramming it goes back to the end of the ready queue (len(ready)), behind those already waiting: fair, first-come first-served sharing. Without multiprogramming it goes back to the front (0), because the program that was running has to finish before the next one starts.
This is the trace of the first 120 ms in multiprogrammed mode (each row is a span in which nothing changes):
| Span (ms) | CPU | Waiting for I/O | What happens |
|---|---|---|---|
| 0-40 | C | — | The compiler computes its first 40 ms |
| 40-50 | D | C | C goes to its I/O; the download gets in |
| 50-60 | M | C, D | D waits 60 ms for the network; Spotify gets in |
| 60-100 | C | D, M | C has finished its I/O (40 + 20 = 60) and comes back; it ends at 100 ms |
| 100-110 | M | D | M finished its wait at 60 + 40 = 100 ms |
| 110-120 | D | M | D finished its wait at 50 + 60 = 110 ms |
What to observe in the output:
- CPU busy time doesn’t change (140 ms): multiprogramming doesn’t make the CPU compute less or faster; it removes dead time.
- Total time drops from 360 to 190 ms, and CPU usage rises from 39% to 74%.
- C finishes at 100 ms in both modes: here the compiler isn’t penalised, because when it comes back from its I/O the CPU is free. The winners are D and M, which no longer have to wait for C to finish completely.
- There are still dots in the multiprogrammed line (from 120 to 150 ms and from 160 to 180 ms): when everyone is waiting for I/O, the CPU has nobody to run. More processes in memory usually cover those gaps… at the cost of more competition for memory.
- Change the data: set
'C': [40, 20, 40, 20, 40]or a download with longer waits and see how the total and the percentage change.
Summary
| Concept | What you need to know |
|---|---|
| Operating system | Software that manages the hardware and gives applications an execution environment; its kernel is always running |
| Roles | Traffic police, facilitator and government |
| OS as an interface | Layer that wraps the hardware: an extended machine that hides and adds; GUI, NUI, CLI (shell) and API |
| System calls | Public kernel services requested through the API (write(fd, buffer, size)) |
| Benefits of the interface | Usability, security, portability, interoperability, maintainability and productivity |
| OS as a manager | Scarce resources, competing processes: which process, how much, when and for how long |
| Criteria | Performance, fairness and security (confidentiality, integrity, availability), in conflict |
| Multiprogramming | Several processes in memory; if one waits for I/O, the CPU runs another (concurrency) |
| Milestones | Multiprogramming, paging, virtual memory, files, uniform I/O, concurrent access, protection |
| Types | Batch (JCL), time sharing, real time, multi-user, SMP/AMP, UMA/NUMA, distributed, virtual machines |
Three ideas to take away:
- The OS sits in the middle: it manages the hardware below and serves the applications above, and it can be seen in two ways, as an interface and as a resource manager.
- Your program never touches the hardware: it asks the kernel with system calls, and that brings usability, security and portability.
- Multiprogramming uses I/O waits so the CPU never rests, and with it come scheduling, memory protection and the concurrency problems we’ll see in the next topics.
Now it’s time to prove it: in the exam-style exercises for What is an operating system you’ll find an interactive quiz with every exam format, a multiprogramming calculation and open-answer questions. And in the next topic we go down one floor: the hardware that supports the operating system (I/O, interrupts, the memory hierarchy and protection).
Next step: exercisesWhat is an operating system — exam-style exercises with your laptop, multiprogramming measured in milliseconds and the types of systems (and the extra tick that cost me points)Did this article help you? Here is how you can support SergioLearns →


What is an operating system — theory with your laptop on a study afternoon, a write() call and a CPU that never rests (and the three programs that weren’t running at the same time)