Professional C++, 3rd Edition

Professional C++, 3rd EditionReviews
Author: Marc Gregoire
Pub Date: 2014
ISBN: 978-1-118-85813-4
Pages: 987
Language: English
Format: PDF
Size: 12 Mb

Download

It is also one of the most difficult programming languages to master. While most competing books are geared toward beginners, Professional C++, Third Edition, shows experienced developers how to master the latest release of C++, explaining little known features with detailed code examples users can plug into their own codes. More advanced language features and programming techniques are presented in this newest edition of the book, whose earlier editions have helped thousands of coders get up to speed with C++. Become familiar with the full capabilities offered by C++, and learn the best ways to design and build applications to solve real-world problems. Professional C++, Third Edition has been substantially revised and revamped from previous editions, and fully covers the latest (2014) C++ standard. Discover how to navigate the significant changes to the core language features and syntax, and extensions to the C++ Standard Library and its templates. This practical guide details many poorly understood elements of C++ and highlights pitfalls to avoid.

+

Cancelling Threads
The standard does not include any mechanism for cancelling a running thread
thread. The best way to achieve this is to provide some communication mecha
threads agree upon. The simplest mechanism is to have a shared variable, whi
checks periodically to determine if it should terminate. Other threads can set t
indirectly instruct the thread to shut down. Care has to be taken to avoid race
coherency problems with reading and writing to this shared variable. Atomic v
variables, both discussed later in this chapter, can help avoid these problems.

Retrieving Results from Threads
As you saw in the previous examples, launching a new thread is pretty easy. However, in most
cases you are probably interested in results produced by the thread. For example, if your thread
performs some mathematical calculations, you really would like to get the results out of the thread
once the thread is finished. One way is to pass a pointer or reference to a result variable to the
thread in which the thread stores the results. Another method is to store the results inside a class
member variable of a function object, which you can retrieve later once the thread has finished
executing.
However, there is another and easier method to obtain a result from threads: futures. They also
make it easier to handle errors that occur inside your threads. Futures are discussed later in this
chapter.

Copying and Rethrowing Exceptions
The whole exception mechanism in C++ works perfectly, as long as it stays within one single thread.
Every thread can throw its own exceptions, but they need to be caught within their own thread.
Exceptions thrown in one thread cannot be caught in another thread. This introduces quite a
few problems when you would like to use exception handling in combination with multithreaded
programming.
Without the standard threading library it’s very difficult if not impossible to gracefully handle
exceptions across threads. The standard threading library solves this issue with the following
exception-related functions. These functions not only work with std::exceptions, but with all
kinds of exceptions, ints, strings, custom exceptions, and so on:
exception_ptr current_exception() noexcept;
This function is intended to be called from inside a catch block, and returns an exception_ptr
object that refers to the exception currently being handled, or a copy of the currently
handled exception, or a null exception_ptrobject if no exception is being handled. This
referenced exception object remains valid for as long as there is an object of type exception_ptr
that is referencing it. exception_ptris of type NullablePointer, which means it can easily be tested
with a simple ifstatement, as the example later in this section demonstrates:
[[noreturn]] void rethrow_exception(exception_ptr p);
This function rethrows the exception referenced by the exception_ptrparameter. Rethrowing the
referenced exception does not have to be done in the same thread that generated the referenced
exception in the first place, which makes this feature perfectly suited for handling exceptions
across different threads. The [[noreturn]]attribute makes it clear that this function never returns
normally. Attributes are introduced in Chapter 10.
template exception_ptr make_exception_ptr(E e) noexcept;
This function creates an exception_ptrobject that refers to a copy of the given exception object.
This is basically a shorthand notation for the following code:

try {
throw e;
} catch(…) {
return current_exception();
}
Let’s see how handling exceptions across different threads can be implemented using these features.
The following code defines a function that does some work and throws an exception. This function
will ultimately be running in a separate background thread:
void doSomeWork()
{
for (int i = 0; i < 5; ++i) {
cout << i << endl;
}
cout << “Thread throwing a runtime_error exception…” << endl;
throw runtime_error(“Exception from thread”);
}
The following threadFunc()function wraps the call to the preceding function in a try/catch
block, catching all exceptions that doSomeWork()might throw. A single argument is supplied to
threadFunc(), which is of type exception_ptr&. Once an exception is caught, the function current_
exception()is used to get a reference to the exception being handled, which is then assigned to the
exception_ptrparameter. After that, the thread exits normally:
void threadFunc(exception_ptr& err)
{
try {
doSomeWork();
} catch (…) {
cout << “Thread caught exception, returning exception…” << endl;
err = current_exception();
}
}
The following doWorkInThread()function is called from within the main thread. Its responsibility
is to create a new thread and start executing threadFunc()in it. A reference to an object of
type exception_ptris given as argument to threadFunc(). Once the thread is created, the
doWorkInThread()function waits for the thread to finish by using the join()method, after which

the error object is examined. Since exception_ptris of type NullablePointer, you can easily check
it using an ifstatement. If it’s a non-null value, the exception is rethrown in the current thread,
which is the main thread in this example. By rethrowing the exception in the main thread, the
exception has been transferred from one thread to another thread.
void doWorkInThread()
{
exception_ptr error;
// Launch background thread
thread t{ threadFunc, ref(error) };
// Wait for thread to finish
t.join();
// See if thread has thrown any exception
if (error)
{
cout << “Main thread received exception, rethrowing it…” << endl;
rethrow_exception(error);
}
else
cout << “Main thread did not receive any exception.” << endl;
}
The main()function is pretty straightforward. It calls doWorkInThread()and wraps the call in a
try/catchblock to catch exceptions thrown by any thread spawned by doWorkInThread():
int main()
{
try {
doWorkInThread();
} catch (const exception& e) {
cout << “Main function caught: ‘” << e.what() << “‘” << endl;
}
}
The output is as follows:
0
1
2
3
4
Thread throwing a runtime_error exception…
Thread caught exception, returning exception…
Main thread received exception, rethrowing it…
Main function caught: ‘Exception from thread’
To keep this example compact and easier to understand, the doWorkInThread()function is
using join()to block and wait until the thread is finished. Of course, in real-world applications
you do not want to block your main thread. For example, in a GUI application, you might
let threadFunc()send a message to the UI thread with, as argument, a copy of the result of
current_exception().