.NET Zone is brought to you in partnership with:

I’m a swiss Master student in Computer Science. I’m very interested in C++, open source projects, Linux, Intel Assembly and Agile. I'm currently working on Eddi, a new programming language that I created to improve my skills in C++. I've also worked a lot on Java technologies (Sprint, Osgi, Play!, ...), but I'm not currently working with Java anymore. Baptiste is a DZone MVB and is not an employee of DZone and has posted 51 posts at DZone. You can read more from them at their website. View Full User Profile

C++11 Concurrency – Part 1 : Start Threads

03.23.2012
| 4313 views |
  • submit to reddit

This post is the first of a series of posts about the new thread library of C++11.

C++11 introduced a new thread library. This library includes utilities for starting and managing threads. It also contains utilities for synchronization like mutexes and other locks, atomic variables and other utilities. In this series of posts, I will try to explain most of the features provided by this new library.

To compile the samples of this article, you will need a compiler with C++11 support. In my case, I used GCC 4.6.1 (you need to pass the -c++0x or -c++11 option to get the C++11 support activated).

Starting threads

Starting a new thread is very easy. When you create an instance of a std::thread, it will automatically be started. When you create a thread you have to give it the code it will execute. The first choice for that, is to pass it a function pointer. Let’s start with the very common Hello World:

#include <thread>
#include <iostream>
 
void hello(){
    std::cout << "Hello from thread " << std::endl;
}
 
int main(){
    std::thread t1(hello);
    t1.join();
 
    return 0;
}

All the threads utilities are located in the thread header. An interesting thing in this first example is the call to the join() function. Calling this function forces the current thread to wait for the other one (in this case, the main thread has to wait for the thread t1 to finish). If you omit this call, the result is undefined. The program can print Hello from thread and a new line, can print just Hello from thread without new line or can print nothing. That’s because the main thread can return from the main function before the t1 thread finishes its execution.

Distinguishing threads

Each thread has a single id allowing us to distinguish each of them. The std::thread class has a get_id() function returning an unique id for this thread. You can get a reference to the current thread with the std::this_thread variable. The next example starts with threads and each of them prints its id:

#include <thread>
#include <iostream>
#include <vector>
 
void hello(){
    std::cout << "Hello from thread " << std::this_thread::get_id() << std::endl;
}
 
int main(){
    std::vector<std::thread> threads;
 
    for(int i = 0; i < 5; ++i){
        threads.push_back(std::thread(hello));
    }
 
    for(auto& thread : threads){
        thread.join();
    }
 
    return 0;
}

Starting each thread one after one and then storing them into a vector is a common way to handle several threads. With that, you can easily change the number of threads. Even with a very little sample like this one, the results is not predictable. The theoretic case:

Hello from thread 140276650997504
Hello from thread 140276667782912
Hello from thread 140276659390208
Hello from thread 140276642604800
Hello from thread 140276676175616

 

Is, in my case, also the less common. You can also get results like this one:

Hello from thread Hello from thread Hello from thread 139810974787328Hello from thread 139810983180032Hello from thread
139810966394624
139810991572736
139810958001920

 

Or a lot of another results. This is because of interleaving. You have no way to control the order of execution of threads. A thread can be preempted at any moment and the appends to the out stream are made one after one (first the append of the string, then append the id and finally the new line), so a thread can print its first part and then be interrupted to print its second part after all the others threads.

Start a thread with a lambda

When the code that has to be executed by each thread is very small, you don’t necessary want to create a function for that. In that case, you can use a lambda to define the executed by a thread. We can rewrite the code of the last sample using lambda easily:

#include <thread>
#include <iostream>
#include <vector>
 
int main(){
    std::vector<std::thread> threads;
 
    for(int i = 0; i < 5; ++i){
        threads.push_back(std::thread([](){
            std::cout << "Hello from thread " << std::this_thread::get_id() << std::endl;
        }));
    }
 
    for(auto& thread : threads){
        thread.join();
    }
 
    return 0;
}

Here we just used a lambda expression instead of the function pointer. Of course, this produces the exact same result as the previous sample.

Next

In the next post of this series, we will see how to protect code using locks.

The source code for each sample is available on Github.

 

Published at DZone with permission of Baptiste Wicht, author and DZone MVB. (source)

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)