Professional C__ - Marc Gregoire [390]
Thread with Lambda
Because the threading library is new in C++11, the C++11 lambda expression feature fits nicely with it, as demonstrated in the following example:
int main()
{
cout.sync_with_stdio(true); // Make sure cout is thread-safe
thread t1([](int id, int numIterations) {
for (int i = 0; i < numIterations; ++i) {
cout << "Counter " << id << " has value ";
cout << i << endl;
}
}, 1, 5);
t1.join();
return 0;
}
Code snippet from thread\ThreadLambda.cpp
Thread with Member Function
The previous examples illustrate different methods of specifying the thread code:
A global function
A function object using operator()
A lambda expression
However, these are not the only techniques available; you can also specify a member function of a class.
The following example defines a basic Request class with a process() method. The main() function creates an instance of the Request class and launches a new thread, which will execute the process() member function of the Request instance, req:
class Request
{
public:
Request(int id) : mId(id) { }
void process()
{
cout << "Processing request " << mId << endl;
}
protected:
int mId;
};
int main()
{
cout.sync_with_stdio(true); // Make sure cout is thread-safe
Request req(100);
thread t{&Request::process, &req};
t.join();
return 0;
}
Code snippet from thread\ThreadMemFunc.cpp
With this technique you are executing a method on a specific object in a separate thread. If other threads are accessing the same object, you need to make sure this happens in a thread-safe way to avoid race conditions. Mutual exclusion, discussed later in this chapter, can be used as synchronization mechanism to make it thread-safe.
Thread Local Storage
C++11 supports the concept of thread local storage. With a new keyword called thread_local, you can mark any variable as thread local, which means that each thread will have its own unique copy of the variable and it will last for the entire duration of the thread. For each thread, the variable is initialized exactly once. This is very similar to a static variable, except that each thread will have its own unique instance of the thread local variable. For example, in the following code, every thread shares one-and-only-one copy of k, while each thread has its own unique copy of n:
thread_local int n;
int k;
void doWork()
{
// perform some computation
}
Note that if the thread_local variable is declared in the scope of a function, its behavior is as if it were declared static, except that every thread has its own unique copy and it is initialized exactly once per thread, no matter how many times that function is called in that thread.
Cancelling Threads
The standard does not include any mechanism for cancelling a running thread from inside another thread. The best way to achieve this is to provide some communication mechanism that the two threads agree on. The simplest mechanism is to have a shared variable which the target thread checks periodically to determine if it should terminate. Other threads can set this shared variable to indirectly instruct the thread to shut down.
A second method is to use condition variables, discussed later in this chapter.
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 will store the results. Another method is to store the results inside a class member variable, which you can retrieve later once the thread has finished executing.
However, there is another and easier method to obtain a result from threads: