A little while back, I ran across a rant about multithreaded programming on The Register (NSFW due to strong language), which starts out with this paragraph:

I don’t know about you, but every time I have to program with threads and shared resources, I want to remove my face incrementally with a salad fork. Locks, mutexes, the synchronized keyword; all of these things can strike fear into the heart of a green developer. Most seasoned developers just fall into a rut of depression when it’s time for multi-threading. Developers like me simply talk our way out of it. It’s easier than thinking.

I was rather bemused by this, but I figured that some developers probably didn’t like writing multithreaded programs, just as some passionately despise pointers or date calculations.

But a few days ago, I was reading a FAQ page and discovered the comment “Threads are evil. Avoid them.” At this point, I decided I had to speak out.

Multithreaded programming is not that hard to master. There are a few extra things you have to do, and there are a few new problems to watch out for, but if you follow a straightforward set of rules, it’s easily possible to write good — and safe — multithreaded programs.

I can’t offer a complete list of these rules. I learned them the hard way; they’re embedded in the way I write code. But here are a few of them off the top of my head, geared toward C++ code:

Know when not to use it. Multithreading is powerful, but so is dynamite — and like dynamite, you have to treat it with respect, or it’ll blow your arm off. Multithreaded programming can be very useful in some cases, but most of the time it’s not called for.

Have each thread do a completely separate task. If your program can’t be split up into tasks that can be run mostly independent of one another, don’t even attempt it.

Don’t pass automatic variables (by reference or pointer) between threads. Automatic variables (in C and C++, at least) are created on the current thread’s stack; when they go out of scope in that thread, the memory is no longer safe to access in any thread. Passing non-array variables of built-in data types by value is generally safe, but that’s all I can promise.

For any variable that uses allocated memory and crosses threads, use reference-counting, with automatic cleanup in its destructor. You don’t know when it’s safe to delete such a variable. The Boost library’s shared_ptr , or something similar, is the way to go for that kind of thing.

Whenever possible, use a specific resources (file, block of memory, whatever) in one thread only. Try to avoid having two or more threads operating on the same block of data or the same file simultaneously. If you have to share a resource between threads, create a thread-safe interface for it — a C++ class that encapsulates it, for example. Then you can control all access to it, and use critical section or mutexes to prevent threads from trying to use it simultaneously.

Be careful with libraries. There are a lot of useful code libraries out there that can’t safely be used by multiple threads simultaneously. A lot of programmers these days rely heavily on bits of code written by other people. That’s fine — if you know exactly what’s going on in it. If you don’t, and the author doesn’t provide any assurance that it’s thread-safe, then you have to assume that it isn’t.

Watch out for cyclical dependencies. If a thread locks a resource, make sure it can’t wait on another resource that might be locked by a different thread that could also be waiting on the first resource — that will lock your program up tighter than Fort Knox. I can’t completely articulate the way I avoid this problem, but it involves knowing exactly what each thread in your program is responsible for, and what resources each one uses.

Basically, you just have to know your code and how the different threads might interact. It takes some practice to get it right — and it’s not the kind of thing you want to practice on with a program that other people are going to use — but it’s really not difficult once you get the hang of it.