Here's an interesting post on multi-threaded (OS level) vs. single threaded application development - I found this via a pointer to KBM's post from the Smalltalk IRC channel. The basic point - if you think you need multiple threads, what you actually need is multiple processes. First, Guido Rossum, the guy behind Python:
I personally don’t think the threaded programming model as found in Java works all that well; without locks you end up with concurrent modification errors, with locks you get deadlocks and livelocks. A typical programmer has a hard enough time keeping track of a bunch of variables being modified by a single thread; add multiple threads acting simultaneously on the same variables to the mix, and it’s a nightmare.
If my hunch is right, I expect that instead of writing massively parallel applications, we will continue to write single-threaded applications that are tied together at the process level rather than at the thread level…. I expect that most problems (even most problems that we will be programming 10-20 years from now) get little benefit out of MP.
Next, Richard Hipp, the SQLLite guy:
This seems like a good opportunity to repeat my oft-ignored advice to not use more than one thread in a single address space. If you need multiple threads, create multiple processes. This has nothing to do with SQLite – it is just good programming advice. I have worked on countless multi-threaded programs over the years, and I have yet to see a single one that didn’t contain subtle, hard to reproduce, and very hard to troubleshoot bugs related to threading issues.
I am constantly amazed at the prevailing idea (exemplified by Java) that software should be strongly typed and should not use goto statement or pointers – all in the name of reducing bugs – but that it is OK to use multiple threads within the same address space. Strong typing helps prevent only bugs that are trivially easy to locate and fix. The use of goto statements and pointers likewise results in deterministic problems that are easy to test for and relatively easy to track down and correct. But threading bugs tend to manifest themselves as timing-dependent glitches and lock-ups that are hardware and platform dependent, that never happen the same way twice, and that only appear for customers after deployment and never in a testing environment.
Now, some will pop up at this point and say that non-OS threads (like VisualWorks Smalltalk has) raise the same problems. The answer is, no they don't. Why? Well, the process model for VisualWorks processes is written in Smalltalk, at the image level. That means that you as the developer have complete control over lightweight process semantics. If you don't like the process model, it's simple to implement a different one, because you don't need to dive into the VM to do it.
Consider threads in Java or C#, by contrast. You have process semantics that are completely out of your control, and vary by platform. An application that uses native threads on Windows will not work the same way on Linux, even though all the source code is the same. You'll end up with mysterious issues that you have no ability to deal with. A VisualWorks application using Smalltalk processes will behave identically on any supported platform. Which makes delivery a whole lot simpler - you don't have to pray that it will work on a different platform. In practice, the porting issues I've faced have always been my fault - a stubborn refusal on my part to deal with file path differences in settings files :)
To get back to the article, clever devil summarizes the above thusly:
So if you shouldn’t use threads, what should you use? Well, Guido said it himself: “write single-threaded applications that are tied together at the process level rather than at the thread level.” Not only will this work very well, it will keep your code simpler, and let you break down problems into smaller chunks. Thats a big deal when working on projects of any size, and multiple process solutions have proven themselves to be effective for years.
Consider that last point well - people have been writing multi-process applications that scale very well for a very long time - Apache being a recent example. It's a well understood architecture, and the inter-process communication possibilities are well known as well - it's a solved problem.