2013: Advent Computing: Threads, trains and tortured analogies

by on December 13, 2013

Imagine you’re running the train network. You have a whole bunch of train tracks, a whole bunch of people to get from one place to another, and just one train to do it with. Simple, right? Move your train from place to place, and let people get on and off as appropriate. It’s not very fast, but there’s not much that can go wrong.

If you want to speed things up, you might get a few trains. Of course, keeping track of multiple trains is hard work, so you only have one train in each bit of your railway network to avoid them crashing. You also only have one driver (thankfully these trains are remote controlled), so you make sure there’s only one train moving at a time. This still gives you a speed increase, though: you can have one train moving while another is waiting at a station for passengers to get on.

As passenger numbers increase, you start letting multiple trains work in the same area. This is much harder: even though only one train will be moving at any one time, it’s hard to keep track of where they all are, and train crashes really aren’t helpful. You start coming up with a bunch of clever tricks to make sure the trains aren’t going to collide or get in each other’s way, such as making some bits of track one-way, or having systems that will stop one train entering a section of track while there’s another one already there.

Finally you start hiring a bunch of drivers to help. Now you have multiple trains running around your railway, moving at the same time over the same bits of track, and while this is obviously a hell of a lot quicker, you need to be really careful about making sure you don’t allow two trains to get too close or to try to head in opposite directions down the same track.

This is effectively how “threading” has evolved in computing. The first computers, while they could be programmed to do any particular thing, would only do one thing at once. Want your computer to work on a different calculation? Drive your train to a different bit of the railway.

The advent of operating systems allowed multiple programs to run on the same computer nominally at the same time. The programs had to be careful about not overwriting each others memory, so they would take a small chunk of the computer’s entire memory and reserve it, just as our trains stuck to a single part of the railway network.

“Multi-threaded” programs are equivalent to having multiple trains serving the same bit of the railway. While one “thread” of the program is waiting for something (such as user input or reading some data from the hard disk) we think of it as sitting at the station. During that time, another thread of the program can carry on with calculations.

Having multiple train drivers is our multi-core computer processors. This is the final trick from yesterday, where our computer performs multiple calculations on each processor cycle. Depending on exactly what the programs on our computer are doing, each “core” of the computer processor might be looking after a different thread from the same program (that is, a different train in the same section of the railway), different threads in different programs (that is, trains in different parts of the railway network), or some combination of both.

Tomorrow I’ll describe some of the ways we avoid our hypothetical trains from crashing into each other. And while the analogy may be somewhat tortured, many of the tricks we use when writing multi-threaded programs are actually used on real train networks too.

Leave a Reply