C++11 Concurrency - Part 1 : Start Threads

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 serie 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 "-std=c++0x" or "-std=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 manipulate the current thread with the functions from the std::this_thread namespace. 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 least 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.

Related articles

  • Java Concurrency - Part 1 : Threads
  • Java Concurrency : Part 2 - Manipulate Threads
  • C++11 Concurrency Tutorial - Part 3: Advanced locking and condition variables
  • C++11 Concurrency Tutorial - Part 2 : Protect shared data
  • Java Concurrency - Part 7 : Executors and thread pools
  • Java Concurrency – Part 3 : Synchronization with intrinsic locks
  • Comments

    Comments powered by Disqus