Skip Navigation Links | |
Exit Print View | |
Oracle Solaris Studio 12.3: C++ User's Guide Oracle Solaris Studio 12.3 Information Library |
3. Using the C++ Compiler Options
6. Creating and Using Templates
9. Improving Program Performance
10. Building Multithreaded Programs
10.1 Building Multithreaded Programs
10.1.1 Indicating Multithreaded Compilation
10.1.2 Using C++ Support Libraries With Threads and Signals
10.2 Using Exceptions in a Multithreaded Program
10.4 Memory Barrier Intrinsics
12. Using the C++ Standard Library
The C++ Standard Library (libCstd -library=Cstd) is MT-safe with the exception of some locales. It ensures that the internals of the library work properly in a multithreaded environment. You still need to place locks around any library objects that you yourself share between threads. See the man pages for setlocale(3C) and attributes(5).
For example, if you instantiate a string, then create a new thread and pass that string to the thread by reference, then you must add locks around write accesses to that string because 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 locking (synchronization) mechanism used internally in the C++ Standard Library to ensure correct behavior in the presence of multiple threads can be described as follows:
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:
void acquire()–Acquires a lock on self, or blocks until such a lock can be obtained.
void release()–Releases a lock on self.
class _RWSTDMutex { public: _RWSTDMutex (); ~_RWSTDMutex (); void acquire (); void release (); };
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. // }