Why threads are a bad idea (for most purposes) – Ousterhout 1995
Today is part 2 of 5 in a week dedicated to threads and events. Yesterday we saw the argument from Lauer and Needham that thread-based and event-based models are equivalent (duals). Despite that, Oustehout would have you believe that threads are a bad idea and we should mostly be using events. This isn’t strictly a paper (it’s a presentation that Ousterhout gave to a Usenix conference), but it has been accepted into the literature as if it were.
What’s so bad about threads then? They are “too hard for most programmers to use, and even for experts development is painful.”
Threads are hard because:
- You have to explicitly coordinate access to shared date with locks. If you forget a lock, you’ll end up with corrupted data.
- Circular dependencies amongst locks can lead to deadlocks
- They are hard to debug with subtle timing issues
- Callbacks don’t work with locks
- It’s hard to get good performance
- Threads aren’t well supported (in the libraries available as of 1996)
Events on the other hand ‘avoid concurrency as much as possible,’ making it easier to get started with event-based systems. They are also claimed to be faster and more portable.
The wonderful Java Concurrency in practice by Brian Goetz (was that really 8 years ago!!) takes just over 350 pages to show you all the ways concurrent programming with threads can be hard. Here’s an excerpt from the section discussing why GUIs tend to use a single-threaded event loop:
Multithreaded GUI frameworks tend to be particularly susceptible to deadlock, partially because of the unfortunate interaction between input event processing and any sensible object-oriented modeling of the GUI components. Actions initiated by the user tend to ‘bubble up’ from the OS to the application – a mouse click detected by the OS, is turned into a ‘mouse click’ event by the toolkit, and is eventually delivered to an application listener as a higher level event such as a ‘button pressed’ event. On the other hand, application-initiated actions ‘bubble down’ from the application to the OS – changing the background colour of a component originates in the application and is dispatched to a specific component class and eventually into the OS for rendering. Combining this tendency for activities to access the same GUI objects in the opposite order with the requirement of making each object thread-safe yields a recipe for inconsistent lock ordering, which leads to deadlock. And this is exactly what nearly every GUI toolkit development effort rediscovered through experience.
(Chapter 9, p.190).
You should avoid threads wherever possible: use events, not threads, for GUIs, distributed systems, and low-end servers; only use threads where true CPU concurrency is needed. If threads are needed, isolate usage in a threaded application kernel and keep most of the code single threaded.
So much for the dual! Before you get too excited about events though, tomorrow we’ll look at a paper entitled “Why events are a bad idea….”!
It’s a shame this argument is only available in presentation form – after writing up so many papers it’s glaringly obvious how poor the presentation format is for this kind of material vs a well-written paper.