I understand if one were using a lot of widely scoped state, it's a bad idea but how about immutable computations and highly localized side effects?
Debugging multi-threaded code is hard. Really hard.
While mitigating state, and proper design can reduce this difficulty it still remains much more difficult than debugging single threaded code.
Thus multi-threading for multi-threading's sake is a design pathology.
That being said, there are plenty of cases where using >1 thread is the right decision.
To over-simplify things, functional languages such as Erlang and Haskell are built around the notion that multithreaded apps are very safe when you eliminate side effects. You should read about those. Also, in general a multithreaded application with no shared state is quite safe.
http://en.wikipedia.org/wiki/Haskell%5F%28programming%5Flanguage%29
http://en.wikipedia.org/wiki/Erlang%5F%28programming%5Flanguage%29
Multithreaded programming isn't considered harmful, but rather notoriously difficult to be done right. There are many things that aren't evident from the first sight and may lead to things like deadlocks and race conditions.
Immutable computations and functional programming is one way to deal with the complexity of multithreaded programming. With multi-core systems becoming ubiquitous today, there is a general consensus that the programmer shouldn't be left on his own to program in mulithread environment, but rather she should rely on a framework or a library. In .NET environment parallel extensions will be part of the 4.0 version of the framework for example.
A lot of people approach multi-threading as if it were the silver bullet to peformance problems. Take for example the relatively common case of doing a "computationally intense operation", the operation is irrelevant.
A common misconception is that by making the operation multi-threaded we can speed it up. The specifics of this are much more complicated. It depends on what the process is and how much "waiting" there is in the process. If the process is very tight, putting it into a multi-threaded environment will at best speed it up marginally, and in most cases it will make it considerably slower.
There are also the consideration of managing state, managing thread interaction and the problems with determinism introduced by threads.
The list of course goes on from there.
The algorithm that you are using in your single-threaded program may or may not be easy to scale to multiple threads.
For example, if you want to do multi-threaded image compression, some formats are inherently tiled, so you can assign a thread to each tile, but for example Lossless JPEG is based on nearest neighbour prediction, so the value of the last pixel is potentially dependent on all the values in between, and therefore this algorithm is unsuitable for division among multiple threads.
Multithreading in C++ is hard because (among other things):
- Every modification of a variable must be done within a critical section. It is hard to see from a statical analysis of the source code which variable needs such locking.
- The scope of critical sections must be small enough to avoid performance issues, but using a separate critical section for each variable is often impossible, because multiple variables must be updated simultaneously.
- Nested critical sections must be used hierarchically. However, tools that can enfore this at compile time don't exist.
- When bugs occur, they are often hard to reproduce because of timing issues. Because of this, the code is both hard to test and difficult to debug.
- Stepping through an asynchronous function call is impossible without setting breakpoints manually, because C++ has no built-in threading support.