The original 128K Mac from 1984 came with a single Motorola 68000 processor running at 8 MHz that could only run one app at a time. Yet today’s Macs come with multiple CPU cores that can comfortably run several substantial apps simultaneously, while running a Time Machine backup and other tasks in the background. This brief history outlines the journey between them.
A processor with a single core and no support for multi-tasking runs one sequence of instructions at a time. When those call for an operating system function to be performed, the running app is interrupted to hand control over to the system, and once that has completed, control is passed back to the app. That’s what the first Macs did until Andy Hertzfeld wrote Switcher, released by Apple in April 1985. This allowed th…
The original 128K Mac from 1984 came with a single Motorola 68000 processor running at 8 MHz that could only run one app at a time. Yet today’s Macs come with multiple CPU cores that can comfortably run several substantial apps simultaneously, while running a Time Machine backup and other tasks in the background. This brief history outlines the journey between them.
A processor with a single core and no support for multi-tasking runs one sequence of instructions at a time. When those call for an operating system function to be performed, the running app is interrupted to hand control over to the system, and once that has completed, control is passed back to the app. That’s what the first Macs did until Andy Hertzfeld wrote Switcher, released by Apple in April 1985. This allowed the user to switch between running more than one app, but was still limited to running just one of them at a time.
Multitasking
Over the next couple of years, some third-party utilities were produced to go further than Switcher, but it wasn’t until 1987 that MultiFinder replaced Switcher, and was integrated into System 7 in 1991. Developed by Erich Ringewald and Phil Goldman, this brought cooperative multitasking, which was to become the mainstay of classic Mac OS.
In computers with a single processor core, multitasking is a way of cheating to give the impression that the processor is doing several things at once, when in fact all it’s doing is switching rapidly between two or more different programs. There are two fundamental models for doing that:
- cooperative multitasking, in which individual tasks yield to give others processing time;
- preemptive multitasking, in which a scheduler switches between tasks at regular intervals. When a processor switches from one task to the next, the current task state must be saved so it can be resumed later. Once that’s complete, the next task is loaded to complete the context switch. That incurs overhead, both in terms of processing and in memory storage, which are less when switching between lightweight tasks. Different strategies have been adopted to determine the optimum size of tasks and overhead imposed by context switching, and terminology differs between them, variously using words such as processes, threads and even fibres, which can prove thoroughly confusing.
Classic Mac OS thus has a Process Manager that launches apps in cooperative multitasking. This works well much of the time, but lets badly behaved tasks hog the processor and block other tasks from getting their fair share. It’s greatly aided by the main event loop at the heart of Mac apps that waits for control input to direct the app to perform work for the user. But when an app charges off to spend many seconds tackling a demanding task without polling its main event loop, that app could lock the user out for what seems like an age.
In February 1988 Apple released the first Unix for Macintosh, A/UX, which came with preemptive multitasking. That was added to Mac OS in 1996 in System 7.5.3, in Multiprocessing Services, and further enhanced in Mac OS 8.6 three years later. Cooperative multitasking was also supported by the Thread Manager.
Threads
In 2000 Apple’s hardware and software changed radically. Its first Macs with dual processors came in PowerPC 7400 (G4) chips in Power Mac G4 desktop systems, and Mac OS X brought several types of thread that could be used to manage processing on multiple processors or CPU cores, together with preemptive multitasking. Thread types include low-level Mach threads, higher-level POSIX threads or Pthreads that replaced Multiprocessing Services, Java Threads, Cocoa’s NSThreads, and cooperatively scheduled threads using the Carbon Thread Manager. The following diagram summarises Apple’s current terminology.
In most cases, we’re considering applications with a GUI, normally run from a bundle structure. These can in turn run their own code, such as privileged helper apps used to perform work that requires elevated privileges. In recent years, there has been a proliferation of additional executable code associated with many apps.
When that app is run, there’s a single runtime instance created from its single executable code, and given its own virtual memory and access to system resources that it needs. This is a process, and listed as such in Activity Monitor, for example.
Each process has a main thread, a single flow of code execution, and may create additional threads, perhaps to run in the background. Threads don’t get their own virtual memory, but share that allocated to the process, although they have their own stack. On Apple silicon Macs they’re easy to tell apart as they can only run on a single core, although they may be moved between cores, sometimes rapidly.
Within each thread are individual tasks, each a quantity of work to be performed. These can be brief sections of code and are more interdependent than threads. They’re often divided into synchronous and asynchronous tasks, depending on whether they need to be run as part of a strict sequence.
In 2005 the Power Mac G5 was the first Mac to use dual-core PowerPC G5 processors, then the iMac 17-inch of the following year used Apple’s first Intel Core Duo processor with two cores.
Grand Central Dispatch
In 2009 Mac OS X 10.6 Snow Leopard introduced a new dispatcher, named Grand Central Dispatch (GCD) after Grand Central Station in New York City, and that was enhanced in macOS Sierra a decade later. More recently it has been referred to simply as Dispatch.
At its heart, GCD is a dispatcher managing queues of tasks, activating those that need most to be run, and leaving the less pressing to wait a bit longer. It has its own queues, as well as those assembled by apps. Some are run as simple queues with a first in first out rule, others using sophisticated heuristics to determine relative priorities. There’s a detailed account of GCD internals in Jonathan Levin’s book *OS Internals volume 1, and Apple’s current developer documentation is here.
GCD was introduced for Macs with multiple identical cores, to support their symmetric multiprocessing (SMP), and with the release of the first Apple silicon Macs in November 2020 it has managed queues of threads to be dispatched for execution on two CPU core types, Performance and Efficiency. Core allocation is now managed according to the Quality of Service (QoS) assigned to each thread. When used on SMP processors with no contention for core availability, QoS has limited effects on thread performance, but performance on P and E cores may differ by a factor of 10.
Over the last 41 years, macOS has gained thorough support for getting the best performance from multiple tasks, threads, and processes in chips that contain up to 32 CPU cores of two types – a far cry from that single 68000 processor.