C++ Programming Guide HomeContentsPreviousNextIndex


Chapter 9

Multithreaded Programs

This chapter explains how to build multithreaded programs. It also discusses the use of exceptions and explains how to share C++ Standard Library objects across threads.

For more information about multithreading, see the Multithreaded Programming Guide, the C++ Library Reference, the Tools.h++ User's Guide, and the Standard C++ Library User's Guide.

9.1 Building Multithreaded Programs

All libraries shipped with the C++ compiler are multithreading-safe. If you want to build a multithreaded application, or if you want to link your application to a multithreaded library, you must compile and link your program with the -mt option. This option passes -D_REENTRANT to the preprocessor and passes -lthread in the correct order to ld. For compatibility mode (-compat[=4]), the -mt option ensures that libthread is linked before libC. For standard mode (the default mode), the -mt option ensures that libthread is linked before libCrun.

Do not link your application directly with -lthread because this causes libthread to be linked in an incorrect order.

The following example shows the correct way to build a multithreaded application when the compilation and linking are done in separate steps:

example% CC -c -mt myprog.cc
example% CC -mt myprog.o

The following example shows the wrong way to build a multithreaded application:

example% CC -c -mt myprog.o
example% CC myprog.o -lthread <- libthread is linked incorrectly

9.1.1 Indicating Multithreaded Compilation

You can check whether an application is linked to libthread or not by using the ldd command:

example% CC -mt myprog.cc
example% ldd a.out
libm.so.1 =>      /usr/lib/libm.so.1
libCrun.so.1 =>   /usr/lib/libCrun.so.1
libw.so.1 =>      /usr/lib/libw.so.1
libthread.so.1 => /usr/lib/libthread.so.1
libc.so.1 =>      /usr/lib/libc.so.1
libdl.so.1 =>     /usr/lib/libdl.so.1

9.1.2 Using C++ Support Libraries With Threads and Signals

The C++ support libraries, libCrun, libiostream, libCstd, and libC are multithread safe but are not async safe. This means that in a multithreaded application, functions available in the support libraries should not be used in signal handlers. Doing so can result in a deadlock situation.

It is not safe to use the following in a signal handler in a multithreaded application:

9.2 Using Exceptions in a Multithreaded Program

The current exception-handling implementation is safe for multithreading; exceptions in one thread do not interfere with exceptions in other threads. However, you cannot use exceptions to communicate across threads; an exception thrown from one thread cannot be caught in another.

Each thread can set its own terminate() or unexpected() function. Calling set_terminate() or set_unexpected() in one thread affects only the exceptions in that thread. The default function for terminate() is abort() for the main thread, and thr_exit() for other threads (see Section 5.5 Specifying Runtime Errors).


Note – Thread cancellation (pthread_cancel(3T)) results in the destruction of automatic (local nonstatic) objects on the stack. When a thread is cancelled, the execution of local destructors is interleaved with the execution of cleanup routines that the user has registered with pthread_cleanup_push(). The local objects for functions called after a particular cleanup routine is registered are destroyed before that routine is executed.

9.3 Sharing C++ Standard Library Objects Between Threads

The C++ Standard Library (libCstd), which is multithread-safe, makes sure that the internals of the library work properly in a multithreading environment. You will still need to lock around any library objects that you yourself share between threads (except for iostreams and locale objects).

For example, if you instantiate a string, then create a new thread and pass that string to the thread by reference, then you must lock around write access to that string, since you are explicitly sharing the one string object between threads. (The facilities provided by the library to accomplish this task are described below.)

On the other hand, if you pass the string to the new thread by value, you do not need to worry about locking, even though the strings in the two different threads may be sharing a representation through Rogue Wave's "copy on write" technology. The library handles that locking automatically. You are only required to lock when making an object available to multiple threads explicitly, either by passing references between threads or by using global or static objects.

The following describes the locking (synchronization) mechanism used internally in the C++ Standard Library to ensure correct behavior in the presence of multiple threads.

The interface to this facility (including the names of files, macros, classes, and any class members) as well as the implementation are an internal detail of the library and are subject to change without notice. Backward compatibility is not guaranteed.

Two synchronization classes provide mechanisms for achieving multithreaded safety; _RWSTDMutex and _RWSTDGuard.

The _RWSTDMutex class provides a platform-independent locking mechanism through the following member functions:

The _RWSTDGuard class is a convenience wrapper class that encapsulates an object of _RWSTDMutex class. An _RWSTDGuard object attempts to acquire the encapsulated mutex in its constructor (throwing an exception of type ::thread_error, derived from std::exception on error), and releases the mutex in its destructor (the destructor never throws an exception).

class _RWSTDGuard
{
public:
    _RWSTDGuard (_RWSTDMutex&);
    ~_RWSTDGuard ();
};

Additionally, you can use the macro _RWSTD_MT_GUARD(mutex) (formerly _STDGUARD) to conditionally create an object of the _RWSTDGuard class in multithread builds. The object guards the remainder of the code block in which it is defined from being executed by multiple threads simultaneously. In single-threaded builds the macro expands into an empty expression.

The following example illustrates the use of these mechanisms.

#include <rw/stdmutex.h>;
 
//
// An integer shared among multiple threads.
//
int I;
 
//
// A mutex used to synchronize updates to I.
//
_RWSTDMutex I_mutex;
 
//
// Increment I by one.  Uses an _RWSTDMutex directly.
//
 
void increment_I ()
{
   I_mutex.acquire();  // Lock the mutex.
   I++;
   I_mutex.release();  // Unlock the mutex.
}
 
//
// Decrement I by one.  Uses an _RWSTDGuard.
//
 
void decrement_I ()
{
   _RWSTDGuard guard(I_mutex);  // Acquire the lock on I_mutex.
   --I;
   //
   // The lock on I is released when destructor is called on guard.
   //
}


Sun Microsystems, Inc.
Copyright information. All rights reserved.
Feedback
Library   |   Contents   |   Previous   |   Next   |   Index