A Brief Guide to Writing Thread Safe Code

This technical paper was written by David Clarke of Dragon Thoughts Ltd and is Copyright David Clarke © 1999

This document is a set of guidelines for avoiding some of the major problems caused by multi-threading. It has a primary focus on the Windows 32 bit platforms but has relevance to any operating system.

The purpose of this document is to provide some guidelines to ensure that the most common errors encountered in writing multi-threaded code in C++ are easily avoided.

It does not seek to be a complete reference for multi-threading.

Target Audience

The intended audience is anyone writing multi-threaded code.

General Threading Issues

When writing any multi threaded software on Windows, it is important to be aware of the following:

Things that Must Never be Done

There is a range of techniques that should never be used in multi-threading unless specifically controlled through the use explicit synchronisation objects, which are specifically designed to handle thread interaction issues.

Techniques to be Avoided

There are techniques that are potentially dangerous in a threading environment, and should be avoided unless there is overwhelming reason to perform them.

Techniques that are Safe or Good

Things that must be done

Synchronisation Mechanisms in Windows, using MFC

In general the Kernel objects will still be cleared up and stop blocking other threads when the thread currently using the object crashes. More detailed discussions can be found in see chapter 4, "Synchronisation", of " Multithreading Applications in Win32" by Jim Beveridge and Robert Wiener.

The MFC classes that deal with synchronisation should be used. The six multithreaded classes provided with MFC fall into two categories: synchronisation objects (CSyncObject, CSemaphore, CMutex, CCriticalSection, and CEvent) and synchronisation access objects (CMultiLock and CSingleLock).

Critical Section

A critical section is used to enforce mutual exclusion between thread within a single process. A critical section:

Mutex

A mutex is a kernel object that will enforce mutual exclusion between threads even if they are in different processes. A mutex:

Semaphore

The semaphore is used to keep track of a limited resource. A semaphore:

Event Object

Event objects are used for overlapped I/O and for some custom designed objects. An event object:

Interlocked variable

The Interlocked..() calls are only synchronisation mechanism if they are used for a spin-lock, which is a busy loop that is expected to be running for such as short time that it has minimal overhead. The kernel uses these occasionally. Other than that, interlock variables are primarily useful for reference counting. They:

Summary

Keep information sharing between threads to a minimum.

Information that must be shared should only be shared through the specifically thread safe entities.

If any words or phrases in this document are unfamiliar to you, and you are developing multi-threaded code, find out about them and their implications.

This technical paper was written by David Clarke of Dragon Thoughts Ltd and is Copyright David Clarke © 1999