Online Book Reader

Home Category

Professional C__ - Marc Gregoire [392]

By Root 1433 0

{

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;

}

Code snippet from ExceptionsWithThreads\ExceptionsWithThreads.cpp

The main() function is pretty straightforward. It calls doWorkInThread() and wraps the call in a try/catch block to catch exceptions thrown by any thread spawned by doWorkInThread():

int main()

{

cout.sync_with_stdio(true); // Make sure cout is thread-safe

try {

doWorkInThread();

} catch (const exception& e) {

cout << "Main function caught: '" << e.what() << "'" << endl;

}

return 0;

}

Code snippet from ExceptionsWithThreads\ExceptionsWithThreads.cpp

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 will 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().

MUTUAL EXCLUSION


If you are writing multithreaded applications, you have to be sensitive to sequencing of operations. If your threads read and write shared data, this can be a problem. There are many ways to avoid this problem, such as never actually sharing data between threads. However, if you can’t avoid sharing data, you must provide for synchronization so that only one thread at a time can change the data.

The real problem arises when there are two or more units of data (hardware-level units) which have to be changed as a single atomic action. A simple assignment to a simple scalar variable typically requires no synchronization. For example, on the x86, a 32-bit aligned value is handled atomically at the hardware level and a single transaction requires no explicit synchronization. For example, setting a Boolean variable to false to stop a thread requires no synchronization, but an operation like ++, --, or op= for any given op requires synchronization. Scalars can often be synchronized properly by using the fetch_xyz() operations described earlier in this chapter, but when your data is more complex, and you need to use that data from multiple threads, you must provide synchronization.

C++11 has support for mutual exclusion in the form of mutex and lock classes. These can be used to implement synchronization between threads and are discussed in the next sections.

Mutex Classes

The mutual exclusion classes are all defined in the header file and are in the std namespace. The basic mechanism of using a mutex is as follows:

A thread that wants to read/write to memory shared with other threads tries to lock a mutex object. If another thread is currently holding this lock, the new thread that wants to gain access will block until the lock is released, or until a timeout interval expires.

Once the thread has obtained the lock, it is free to read and write memory which is shared with other threads because at this point it is working under the assumption that no other threads are attempting to read or write the same data.

After the thread is finished with reading/writing to the shared memory it releases the lock to give some other thread an opportunity to obtain the lock to the shared memory. If two or more threads are waiting on the lock, there are no guarantees as to which thread will be granted the lock and thus allowed to proceed.

The standard provides non-timed mutex classes and timed mutex classes discussed in the following sections.

Non-Timed Mutex Classes

The library has two non-timed mutex classes: std::mutex

Return Main Page Previous Page Next Page

®Online Book Reader