Coder: My program needs to read a file that might take longer than one GUI event. What shall I do?
Alleged Guru: Read the kernel manual my child. It discusses the miracle of threads, and it shows for its example reading a file in another thread. You may put a thread in your program, and use a SpinLock on this side until the thread finishes.
See PrematureComplexity.
(In this situation, the correct fix is to read the kernel manual on select() or the equivalent, then multiplex events from your GUI and file system together. Then read the file in slices. Forcing your file reader to store its state between slices improves its design to become EventDriven. It won't store state as the current location of the control flow inside the methods.)
Tutorials describing your language's threading model typically introduce threads as an architectural cure-all:
"Threads enhance performance and functionality in various programming languages -- including Java -- by allowing a program to efficiently perform multiple..."
http://www.javaworld.com/javaworld/jw-04-1996/jw-04-threads.html
False. select() can't be presented as a cure-all,
select() was not presented as a cure-all. It was presented as an example of the tiny bit of research required to avoid the CPU equivalant of Goto
While threads as commonly implemented are indeed a bad approach here, concurrency in general is not. Event-based concurrency as implemented in EeLanguage or other ActorLanguages would be a perfectly reasonable approach, simpler than using select().
The concurrency in this case isn't the problem, not by itself anyway. However, to readily take advantage of this concurrency, better language support is desirable - threads are essentially software representations of additional CPUs, but any language that requires working with threads explicitly does not make safe, scalable, composable, high-performance concurrency easy to achieve.
People are working hard to lower the bar for safe, scalable, composable, high-performance concurrency in programming languages. It is becoming ever more necessary, now that processors are scaling numbers of cores rather than core speed (Tilera is 16 to 100 cores per die).
I'd suggest a different example for this page. Even a very dumb alleged guru wouldn't advocate using a SpinLock in this case.
You may indeed live in a SpinLock-free zone. Count yourself lucky.
In many cases the multi-threaded solution is far simpler. Why go to all the work of making your file reader EventDriven, storing state, reading files in slices, etc. when you can just start a thread that reads the file in the obvious way?
If you need to eat a sandwich with one hand and drive with the other, thread. One good criteria is either process could stand alone. Time slicing is a prod to good design either way.
Don't thread just because you are unaware of alternatives, or because lame tutorials couldn't think of a better example for their thread sections.
Time-slicing a simple file read to implement a poor-man's CooperativeThreading system seems like a very bad design to me.
The distinction is between algorithms that store their state as the location of their control flow in their functions, and those that store state as state. This is the fundamental difference between ProceduralCode and EventDrivenProgramming. Nobody said CooperativeThreading.
{{Languages with better support for MessagePassingConcurrency (i.e. models other than "threads and locks") don't force you to make this largely artificial distinction.}}
But processing a related set of database operations or network messages as an event-driven operation would make sense.
Right. Things that already have a sliced format should express that fact in the code, not hide it.
Consider code that reads characters and writes a simple terminal protocol, such as VT52 or VT100 (but not even both). The poor design calls GetChar() at the bottom of several methods, each one of which does something different (say, the color tag, or the position tag, or something).
The better design calls GetChar() in one place, drops the character into a state machine that knows what display code is currently in progress. The current state in the machine would complete a color tag or position tag, then it would set the next state.
This is an example of replacing procedure with events.
[Personally, I find the thread/procedural approach much easier to code and to understand, in many cases. Explicit state tracking is exactly that -- explicit, requiring thought and effort that the procedural abstraction and the call stack would otherwise take care of for you as a byproduct of writing the algorithm in a straightforward fashion. Locking/rendezvous/message-passing mechanisms can be and often already are nicely encapsulated and easy to use. If a task has only minimal locking and rendezvous interactions with other threads, then it seems far the easier choice to run it in a thread. Add to this modern exception signalling and handling mechanisms, and you even have graceful ways of dealing with failure.-- DanMuller]
Related: MultiThreadedGuiWouldBeGreat | ThreadsConsideredHarmful | EventQueue | EventDrivenProgramming | WaitFreeSynchronization | LockFreeSynchronization | SynchronizationStrategies | ReadyState | CompletionState