Oh, I don't think your, "should I make my app multi-threaded or not?"
question is at all superficial. Note that I never addressed that
question above at all - that was on purpose. I didn't address it
because it's mostly orthogonal to the issues discussed above,
and because it's more contentious, and I'm less sure of the
right answer.
Achieving at least the illusion of concurrency is important for many
apps. (GUIs, moderate traffic web servers, etc.) Currently, the main
ways to get it are either are various flavors of single-cpu user
threads, or event driven code.
Achieving real concurrency - multiple threads of execution running at
the same time on multiple processor cores - is less widely needed -
but if you need it, you may really, really need it. The
trick is that you may not know ahead of time whether you need it or
not. ("Oh awesome, my web service just got hugely popular! Oh shit,
my web service just got hugely popular...")
(Note also that there are many different - some wildly
different - approaches in the basic multiple-threads-of-execution bin.
User threads, OS threads, processes with shared memory, programs on
different physical boxes exchanging messages with MPI or with TCP/IP
sockets, etc.)
In practice I've been quite happy with Tcl's (and AOLserver's)
high-level apartment thread model built on top of real, OS-driven
POSIX threads. So I am biased in that direction. (Note though that
these can be fairly heavyweight threads, often much heavier than the
basic POSIX threads underneath.) There are definitely other
concurrency models in real world production use worth checking out,
though. Erlang is one of those, there are no doubt others.
Also, there is definitely ongoing, much needed research on better
models and tools for concurrent programming. (E.g., there seem to be
academic folks seriously working on replacing locks with transactions.
Also lots of lower level stuff, trying to make efficient use of
"weird" cpu architectures like graphics cards and IBM's Cell, etc.)
My bet is that 15 years from now, we'll be using concurrent
programming tools quite a lot different than the POSIX threads,
MPI-based message passing, etc. that we're using now.
But to get back to the real world of the here and now...
Code that is thread-safe and reentrant is always a plus, because it
gives you the option of using it in a multi-threaded
environment, even if you don't really care to at the moment. But
naturally, software development has trade-offs. Some developers
choose to punt on thread-safety in favor of spending their time
elsewhere. Whether that's a wise trade-off or not in their particular
case, I don't know.
I do know I would try to avoid having to make that trade-off. I tend
to write most of my code in a re-entrant style even if I'm using it
single-threaded. ("Repeat after me class, global variables are
EEEEEvil.")
Multi-threaded Tcl and AOLserver do work very well. This not so much
because they just "use threads", but because they use POSIX threads in
a rather well thought out way, and provide lots of nice APIs to make
doing the right thing fairly easy, and difficult things possible.